| /* Copyright (C) 2012-2016 Free Software Foundation, Inc. | 
 |  | 
 |    This file is part of the GNU C Library. | 
 |  | 
 |    The GNU C Library is free software; you can redistribute it and/or | 
 |    modify it under the terms of the GNU Lesser General Public | 
 |    License as published by the Free Software Foundation; either | 
 |    version 2.1 of the License, or (at your option) any later version. | 
 |  | 
 |    The GNU C Library is distributed in the hope that it will be useful, | 
 |    but WITHOUT ANY WARRANTY; without even the implied warranty of | 
 |    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU | 
 |    Lesser General Public License for more details. | 
 |  | 
 |    You should have received a copy of the GNU Lesser General Public | 
 |    License along with the GNU C Library.  If not, see | 
 |    <http://www.gnu.org/licenses/>.  */ | 
 |  | 
 | /* Assumptions: | 
 |  * | 
 |  * ARMv8-a, AArch64 | 
 |  * Unaligned accesses | 
 |  * | 
 |  */ | 
 |  | 
 | #define dstin	x0 | 
 | #define src	x1 | 
 | #define count	x2 | 
 | #define tmp1	x3 | 
 | #define tmp1w	w3 | 
 | #define tmp2	x4 | 
 | #define tmp2w	w4 | 
 | #define tmp3	x5 | 
 | #define tmp3w	w5 | 
 | #define dst	x6 | 
 |  | 
 | #define A_l	x7 | 
 | #define A_h	x8 | 
 | #define B_l	x9 | 
 | #define B_h	x10 | 
 | #define C_l	x11 | 
 | #define C_h	x12 | 
 | #define D_l	x13 | 
 | #define D_h	x14 | 
 |  | 
 | #include <sysdep.h> | 
 |  | 
 | ENTRY_ALIGN (memcpy, 6) | 
 |  | 
 | 	mov	dst, dstin | 
 | 	cmp	count, #64 | 
 | 	b.ge	L(cpy_not_short) | 
 | 	cmp	count, #15 | 
 | 	b.le	L(tail15tiny) | 
 |  | 
 | 	/* Deal with small copies quickly by dropping straight into the | 
 | 	 * exit block.  */ | 
 | L(tail63): | 
 | 	/* Copy up to 48 bytes of data.  At this point we only need the | 
 | 	 * bottom 6 bits of count to be accurate.  */ | 
 | 	ands	tmp1, count, #0x30 | 
 | 	b.eq	L(tail15) | 
 | 	add	dst, dst, tmp1 | 
 | 	add	src, src, tmp1 | 
 | 	cmp	tmp1w, #0x20 | 
 | 	b.eq	1f | 
 | 	b.lt	2f | 
 | 	ldp	A_l, A_h, [src, #-48] | 
 | 	stp	A_l, A_h, [dst, #-48] | 
 | 1: | 
 | 	ldp	A_l, A_h, [src, #-32] | 
 | 	stp	A_l, A_h, [dst, #-32] | 
 | 2: | 
 | 	ldp	A_l, A_h, [src, #-16] | 
 | 	stp	A_l, A_h, [dst, #-16] | 
 |  | 
 | L(tail15): | 
 | 	ands	count, count, #15 | 
 | 	beq	1f | 
 | 	add	src, src, count | 
 | 	ldp	A_l, A_h, [src, #-16] | 
 | 	add	dst, dst, count | 
 | 	stp	A_l, A_h, [dst, #-16] | 
 | 1: | 
 | 	RET | 
 |  | 
 | L(tail15tiny): | 
 | 	/* Copy up to 15 bytes of data.  Does not assume additional data | 
 | 	   being copied.  */ | 
 | 	tbz	count, #3, 1f | 
 | 	ldr	tmp1, [src], #8 | 
 | 	str	tmp1, [dst], #8 | 
 | 1: | 
 | 	tbz	count, #2, 1f | 
 | 	ldr	tmp1w, [src], #4 | 
 | 	str	tmp1w, [dst], #4 | 
 | 1: | 
 | 	tbz	count, #1, 1f | 
 | 	ldrh	tmp1w, [src], #2 | 
 | 	strh	tmp1w, [dst], #2 | 
 | 1: | 
 | 	tbz	count, #0, 1f | 
 | 	ldrb	tmp1w, [src] | 
 | 	strb	tmp1w, [dst] | 
 | 1: | 
 | 	RET | 
 |  | 
 | L(cpy_not_short): | 
 | 	/* We don't much care about the alignment of DST, but we want SRC | 
 | 	 * to be 128-bit (16 byte) aligned so that we don't cross cache line | 
 | 	 * boundaries on both loads and stores.  */ | 
 | 	neg	tmp2, src | 
 | 	ands	tmp2, tmp2, #15		/* Bytes to reach alignment.  */ | 
 | 	b.eq	2f | 
 | 	sub	count, count, tmp2 | 
 | 	/* Copy more data than needed; it's faster than jumping | 
 | 	 * around copying sub-Quadword quantities.  We know that | 
 | 	 * it can't overrun.  */ | 
 | 	ldp	A_l, A_h, [src] | 
 | 	add	src, src, tmp2 | 
 | 	stp	A_l, A_h, [dst] | 
 | 	add	dst, dst, tmp2 | 
 | 	/* There may be less than 63 bytes to go now.  */ | 
 | 	cmp	count, #63 | 
 | 	b.le	L(tail63) | 
 | 2: | 
 | 	subs	count, count, #128 | 
 | 	b.ge	L(cpy_body_large) | 
 | 	/* Less than 128 bytes to copy, so handle 64 here and then jump | 
 | 	 * to the tail.  */ | 
 | 	ldp	A_l, A_h, [src] | 
 | 	ldp	B_l, B_h, [src, #16] | 
 | 	ldp	C_l, C_h, [src, #32] | 
 | 	ldp	D_l, D_h, [src, #48] | 
 | 	stp	A_l, A_h, [dst] | 
 | 	stp	B_l, B_h, [dst, #16] | 
 | 	stp	C_l, C_h, [dst, #32] | 
 | 	stp	D_l, D_h, [dst, #48] | 
 | 	tst	count, #0x3f | 
 | 	add	src, src, #64 | 
 | 	add	dst, dst, #64 | 
 | 	b.ne	L(tail63) | 
 | 	RET | 
 |  | 
 | 	/* Critical loop.  Start at a new cache line boundary.  Assuming | 
 | 	 * 64 bytes per line this ensures the entire loop is in one line.  */ | 
 | 	.p2align 6 | 
 | L(cpy_body_large): | 
 | 	/* There are at least 128 bytes to copy.  */ | 
 | 	ldp	A_l, A_h, [src, #0] | 
 | 	sub	dst, dst, #16		/* Pre-bias.  */ | 
 | 	ldp	B_l, B_h, [src, #16] | 
 | 	ldp	C_l, C_h, [src, #32] | 
 | 	ldp	D_l, D_h, [src, #48]!	/* src += 64 - Pre-bias.  */ | 
 | 1: | 
 | 	stp	A_l, A_h, [dst, #16] | 
 | 	ldp	A_l, A_h, [src, #16] | 
 | 	stp	B_l, B_h, [dst, #32] | 
 | 	ldp	B_l, B_h, [src, #32] | 
 | 	stp	C_l, C_h, [dst, #48] | 
 | 	ldp	C_l, C_h, [src, #48] | 
 | 	stp	D_l, D_h, [dst, #64]! | 
 | 	ldp	D_l, D_h, [src, #64]! | 
 | 	subs	count, count, #64 | 
 | 	b.ge	1b | 
 | 	stp	A_l, A_h, [dst, #16] | 
 | 	stp	B_l, B_h, [dst, #32] | 
 | 	stp	C_l, C_h, [dst, #48] | 
 | 	stp	D_l, D_h, [dst, #64] | 
 | 	add	src, src, #16 | 
 | 	add	dst, dst, #64 + 16 | 
 | 	tst	count, #0x3f | 
 | 	b.ne	L(tail63) | 
 | 	RET | 
 | END (memcpy) | 
 | libc_hidden_builtin_def (memcpy) |