/* memcopy.h -- definitions for memory copy functions.  Generic C version.
   Copyright (C) 1991 Free Software Foundation, Inc.
   Contributed by Torbjorn Granlund (tege@sics.se).

The GNU C Library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public License as
published by the Free Software Foundation; either version 2 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
Library General Public License for more details.

You should have received a copy of the GNU Library General Public
License along with the GNU C Library; see the file COPYING.LIB.  If
not, write to the Free Software Foundation, Inc., 675 Mass Ave,
Cambridge, MA 02139, USA.  */

/* The strategy of the memory functions is:

     1. Copy bytes until the destination pointer is aligned.

     2. Copy words in unrolled loops.  If the source and destination
     are not aligned in the same way, use word memory operations,
     but shift and merge two read words before writing.

     3. Copy the few remaining bytes.

   This is fast on processors that have at least 10 registers for
   allocation by GCC, and that can access memory at reg+const in one
   instruction.

   I made an "exhaustive" test of this memmove when I wrote it,
   exhaustive in the sense that I tried all alignment and length
   combinations, with and without overlap.  */

#include <endian.h>

/* The macros defined in this file are:

   BYTE_COPY_FWD(dst_beg_ptr, src_beg_ptr, nbytes_to_copy)

   BYTE_COPY_BWD(dst_end_ptr, src_end_ptr, nbytes_to_copy)

   WORD_COPY_FWD(dst_beg_ptr, src_beg_ptr, nbytes_remaining, nbytes_to_copy)

   WORD_COPY_BWD(dst_end_ptr, src_end_ptr, nbytes_remaining, nbytes_to_copy)

   MERGE(old_word, sh_1, new_word, sh_2)
*/

/* Type to use for aligned memory operations.
   This should normally be the biggest type supported by a single load
   and store.  */
#define	op_t	unsigned long int
#define OPSIZ	(sizeof(op_t))

/* Type to use for unaligned operations.  */
typedef unsigned char byte;

/* Optimal type for storing bytes in registers.  */
#define	reg_char	char

#if 0
#ifdef __LITTLE_ENDIAN
#define MERGE(w0, sh_1, w1, sh_2) (((w0) >> (sh_1)) | ((w1) << (sh_2)))
#endif
#ifdef __BIG_ENDIAN
#define MERGE(w0, sh_1, w1, sh_2) (((w0) << (sh_1)) | ((w1) >> (sh_2)))
#endif
#endif

/* Threshold value for when to enter the unrolled loops.  */
#define	OP_T_THRES	8

#define BYTE_COPY_FWD(dst_bp, src_bp, nbytes)				      \
  asm volatile(/* Clear the direction flag, so copying goes forward.  */      \
	       "cld\n"							      \
	       /* Copy bytes.  */					      \
	       "rep\n"							      \
	       "movsb" :						      \
	       "=D" (dst_bp), "=S" (src_bp) :				      \
	       "0" (dst_bp), "1" (src_bp), "c" (nbytes) :		      \
	       "cx")

#define BYTE_COPY_BWD(dst_ep, src_ep, nbytes)				      \
  do									      \
    {									      \
      asm volatile(/* Set the direction flag, so copying goes backwards.  */  \
		   "std\n"						      \
		   /* Copy bytes.  */					      \
		   "rep\n"						      \
		   "movsb\n"						      \
		   /* Clear the dir flag.  Convention says it should be 0. */ \
		   "cld" :						      \
		   "=D" (dst_ep), "=S" (src_ep) :			      \
		   "0" (dst_ep - 1), "1" (src_ep - 1), "c" (nbytes) :	      \
		   "cx");						      \
      dst_ep += 1;							      \
      src_ep += 1;							      \
    } while (0)

#define WORD_COPY_FWD(dst_bp, src_bp, nbytes_left, nbytes)		      \
  do									      \
    {									      \
      asm volatile(/* Clear the direction flag, so copying goes forward.  */  \
		   "cld\n"						      \
		   /* Copy longwords.  */				      \
		   "rep\n"						      \
		   "movsl" :						      \
		   "=D" (dst_bp), "=S" (src_bp) :			      \
		   "0" (dst_bp), "1" (src_bp), "c" ((nbytes) / 4) :	      \
		   "cx");						      \
      (nbytes_left) = (nbytes) % 4;					      \
    } while (0)

#define WORD_COPY_BWD(dst_ep, src_ep, nbytes_left, nbytes)		      \
  do									      \
    {									      \
      asm volatile(/* Set the direction flag, so copying goes backwards.  */  \
		   "std\n"						      \
		   /* Copy longwords.  */				      \
		   "rep\n"						      \
		   "movsl\n"						      \
		   /* Clear the dir flag.  Convention says it should be 0. */ \
		   "cld" :						      \
		   "=D" (dst_ep), "=S" (src_ep) :			      \
		   "0" (dst_ep - 4), "1" (src_ep - 4), "c" ((nbytes) / 4) :   \
		   "cx");						      \
      dst_ep += 4;							      \
      src_ep += 4;							      \
      (nbytes_left) = (nbytes) % 4;					      \
    } while (0)
