/* Highly optimized version for x86-64.
   Copyright (C) 1997, 2000, 2002, 2003, 2004 Free Software Foundation, Inc.
   This file is part of the GNU C Library.
   Based on i586 version contributed by Ulrich Drepper <drepper@cygnus.com>, 1997.

   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, write to the Free
   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
   02111-1307 USA.  */

#include "_glibc_inc.h"

/* BEWARE: `#ifdef memcpy' means that memcpy is redefined as `mempcpy',
   and the return value is the byte after the last one copied in
   the destination. */
#define MEMPCPY_P (defined memcpy)

        .text
#if defined PIC && !defined NOT_IN_libc
ENTRY (__memcpy_chk)
	cmpq	%rdx, %rcx
	jb	HIDDEN_JUMPTARGET (__chk_fail)
END (__memcpy_chk)
#endif
ENTRY (BP_SYM (memcpy))
	/* Cutoff for the big loop is a size of 32 bytes since otherwise
	   the loop will never be entered.  */
	cmpq	$32, %rdx
	movq	%rdx, %rcx
#if !MEMPCPY_P
	movq	%rdi, %r10	/* Save value. */
#endif

	/* We need this in any case.  */
	cld

	jbe	1f

	/* Align destination.  */
	movq	%rdi, %rax
	negq	%rax
	andq	$7, %rax
	subq	%rax, %rcx
	xchgq	%rax, %rcx

	rep; movsb

	movq	%rax, %rcx
	subq	$32, %rcx
	js	2f

	.p2align 4
3:

	/* Now correct the loop counter.  Please note that in the following
	   code the flags are not changed anymore.  */
	subq	$32, %rcx

	movq	(%rsi), %rax
	movq	8(%rsi), %rdx
	movq	16(%rsi), %r8
	movq	24(%rsi), %r9
	movq	%rax, (%rdi)
	movq	%rdx, 8(%rdi)
	movq	%r8, 16(%rdi)
	movq	%r9, 24(%rdi)

	leaq	32(%rsi), %rsi
	leaq	32(%rdi), %rdi

	jns	3b

	/* Correct extra loop counter modification.  */
2:	addq	$32, %rcx
1:	rep; movsb

#if MEMPCPY_P
	movq	%rdi, %rax		/* Set return value.  */
#else
	movq	%r10, %rax		/* Set return value.  */
	
#endif
	ret

END (BP_SYM (memcpy))