Paul Mundt wrote:
On Sun, Mar 25, 2007 at 09:18:33AM -0400, Mike Frysinger wrote:
On Wednesday 21 March 2007, Carmelo AMOROSO wrote:
I'm currently using on uClibc-nptl for sh4 an optimized version
of the memcpy function (from Stuart Menefy @STMicroelectronics).
This implementation is based on 'backward copying'
and brakes the current implementation of 'memmove'
(libc/string/generic/memmove.c)
that, as clearly stated, assumes memcpy does a forward copying.

The attached patch provides a solution for this adding a config option
to specify what kind of memcpy implementation the architecture provides.
In this way the memmove works with both implementation.
if anything, this option should not be exported for the user to try and figure out ... either the architecture provides it or it doesnt which means it'd be a hardcoded selection in the arch-specific config.in files ...

wouldnt it be simpler to provide a superh optimized memmove/memcpy ? then it wouldnt matter what the generic implementations assume ...

It has to be split out separately for sh4, given the movca.l usage.
Hi All,
I've updated the previous patch to keep into account both suggestions made by Mike and Paul.
A brief explanation of the changes follows:

extra/Configs/Config.in -> set the TARGET_SUBARCH for the sh4 architecture extra/Configs/Config.in.sh -> set on the ARCH_HAS_BWD_MEMCPY for sh4 architecture only

libc/string/sh/sh4                  -> new file memcpy.S (sh4 specific)
libc/string/generic/memmove.c -> use the new macro __ARCH_HAS_BWD_MEMCPY__ instead of #if 1 libc/string/generic/memcpy.c -> move static function from C source to common header file with some reorder
libc/string/generic/memcopy.h   ->  ""
libc/string/Makefile.in -> add code the manage subarch specific code in addition to the arch specific one.

Any comments are welcome.

Cheers,
Carmelo
diff -Naupr uClibc-trunk/extra/Configs/Config.in 
uClibc-trunk-st/extra/Configs/Config.in
--- uClibc-trunk/extra/Configs/Config.in        2007-04-24 15:19:31.000000000 
+0200
+++ uClibc-trunk-st/extra/Configs/Config.in     2007-05-07 10:24:22.045984000 
+0200
@@ -180,6 +180,7 @@ config TARGET_SUBARCH
        string
        default "e500" if CONFIG_E500
        default "classic" if CONFIG_CLASSIC
+       default "sh4" if CONFIG_SH4
        default ""
 
 source "extra/Configs/Config.in.arch"
diff -Naupr uClibc-trunk/extra/Configs/Config.sh 
uClibc-trunk-st/extra/Configs/Config.sh
--- uClibc-trunk/extra/Configs/Config.sh        2007-03-16 21:38:22.000000000 
+0100
+++ uClibc-trunk-st/extra/Configs/Config.sh     2007-05-07 14:02:04.426778000 
+0200
@@ -48,3 +48,8 @@ config CONFIG_SH4
        bool "SH4"
 
 endchoice
+
+config ARCH_HAS_BWD_MEMCPY
+       bool
+       default y
+       depends CONFIG_SH4
diff -Naupr uClibc-trunk/libc/string/Makefile.in 
uClibc-trunk-st/libc/string/Makefile.in
--- uClibc-trunk/libc/string/Makefile.in        2006-09-19 09:43:04.000000000 
+0200
+++ uClibc-trunk-st/libc/string/Makefile.in     2007-05-07 10:27:07.516749000 
+0200
@@ -8,6 +8,18 @@
 #
 # Arch specific fun
 #
+# Collect the subarch specific implementation (asm files)
+ifneq ($(strip $(TARGET_SUBARCH)),)
+STRING_SUBARCH_DIR := $(top_srcdir)libc/string/$(TARGET_ARCH)/$(TARGET_SUBARCH)
+STRING_SUBARCH_OUT := 
$(top_builddir)libc/string/$(TARGET_ARCH)/$(TARGET_SUBARCH)
+
+STRING_SUBARCH_SSRC := $(wildcard $(STRING_SUBARCH_OUT)/*.S)
+STRING_SUBARCH_SOBJ := $(patsubst 
$(STRING_SUBARCH_DIR)/%.S,$(STRING_SUBARCH_OUT)/%.o,$(STRING_SUBARCH_SSRC))
+
+STRING_SUBARCH_OBJS := $(STRING_SUBARCH_SOBJ)
+endif
+
+# Collect the arch specific implementation (asm, c files)
 STRING_ARCH_DIR := $(top_srcdir)libc/string/$(TARGET_ARCH)
 STRING_ARCH_OUT := $(top_builddir)libc/string/$(TARGET_ARCH)
 
@@ -15,13 +27,18 @@ STRING_ARCH_SRC := $(wildcard $(STRING_A
 STRING_ARCH_OBJ := $(patsubst 
$(STRING_ARCH_DIR)/%.c,$(STRING_ARCH_OUT)/%.o,$(STRING_ARCH_SRC))
 
 STRING_ARCH_SSRC := $(wildcard $(STRING_ARCH_DIR)/*.S)
-STRING_ARCH_SOBJ := $(patsubst 
$(STRING_ARCH_DIR)/%.S,$(STRING_ARCH_OUT)/%.o,$(STRING_ARCH_SSRC))
 
+# Exclude the subarch implementation from the arch ones
+ifneq ($(strip $(STRING_SUBARCH_OBJS)),)
+STRING_ARCH_SSRC := $(filter-out $(patsubst 
%.o,$(STRING_ARCH_DIR)/%.S,$(notdir 
$(STRING_SUBARCH_OBJS))),$(STRING_ARCH_SSRC))
+endif
+
+STRING_ARCH_SOBJ := $(patsubst 
$(STRING_ARCH_DIR)/%.S,$(STRING_ARCH_OUT)/%.o,$(STRING_ARCH_SSRC))
 STRING_ARCH_OBJS := $(STRING_ARCH_OBJ) $(STRING_ARCH_SOBJ)
 
-libc-$(UCLIBC_HAS_STRING_ARCH_OPT) += $(STRING_ARCH_OBJS)
+libc-$(UCLIBC_HAS_STRING_ARCH_OPT) += $(STRING_ARCH_OBJS) 
$(STRING_SUBARCH_OBJS)
 
-libc-nomulti-$(UCLIBC_HAS_STRING_ARCH_OPT) += $(STRING_ARCH_SOBJ)
+libc-nomulti-$(UCLIBC_HAS_STRING_ARCH_OPT) += $(STRING_ARCH_SOBJ) 
$(STRING_SUBARCH_OBJS)
 
 #
 # Generic stuff
@@ -35,6 +52,9 @@ ifeq ($(UCLIBC_HAS_STRING_ARCH_OPT),y)
 ifneq ($(strip $(STRING_ARCH_OBJS)),)
 STRING_GENERIC_SRC := $(filter-out $(patsubst 
%.o,$(STRING_GENERIC_DIR)/%.c,$(notdir 
$(STRING_ARCH_OBJS))),$(STRING_GENERIC_SRC))
 endif
+ifneq ($(strip $(STRING_SUBARCH_OBJS)),)
+STRING_GENERIC_SRC := $(filter-out $(patsubst 
%.o,$(STRING_GENERIC_DIR)/%.c,$(notdir 
$(STRING_SUBARCH_OBJS))),$(STRING_GENERIC_SRC))
+endif
 endif
 
 STRING_GENERIC_OBJS := $(patsubst 
$(STRING_GENERIC_DIR)/%.c,$(STRING_GENERIC_OUT)/%.o,$(STRING_GENERIC_SRC))
@@ -93,6 +113,9 @@ ifeq ($(UCLIBC_HAS_STRING_ARCH_OPT),y)
 ifneq ($(strip $(STRING_ARCH_OBJS)),)
 STRING_CSRC := $(filter-out $(patsubst %.o,$(STRING_DIR)/%.c,$(notdir 
$(STRING_ARCH_OBJS))),$(STRING_CSRC))
 endif
+ifneq ($(strip $(STRING_SUBARCH_OBJS)),)
+STRING_CSRC := $(filter-out $(patsubst %.o,$(STRING_DIR)/%.c,$(notdir 
$(STRING_SUBARCH_OBJS))),$(STRING_CSRC))
+endif
 endif
 
 ifeq ($(UCLIBC_HAS_STRING_GENERIC_OPT),y)
diff -Naupr uClibc-trunk/libc/string/generic/memcopy.h 
uClibc-trunk-st/libc/string/generic/memcopy.h
--- uClibc-trunk/libc/string/generic/memcopy.h  2006-09-19 09:43:00.000000000 
+0200
+++ uClibc-trunk-st/libc/string/generic/memcopy.h       2007-05-07 
10:27:55.056971000 +0200
@@ -107,24 +107,6 @@ typedef unsigned char byte;
        }                                                                     \
     } while (0)
 
-/* Copy *up to* NBYTES bytes from SRC_BP to DST_BP, with
-   the assumption that DST_BP is aligned on an OPSIZ multiple.  If
-   not all bytes could be easily copied, store remaining number of bytes
-   in NBYTES_LEFT, otherwise store 0.  */
-/* extern void _wordcopy_fwd_aligned __P ((long int, long int, size_t)); */
-/* extern void _wordcopy_fwd_dest_aligned __P ((long int, long int, size_t)); 
*/
-#define WORD_COPY_FWD(dst_bp, src_bp, nbytes_left, nbytes)                   \
-  do                                                                         \
-    {                                                                        \
-      if (src_bp % OPSIZ == 0)                                               \
-       _wordcopy_fwd_aligned (dst_bp, src_bp, (nbytes) / OPSIZ);             \
-      else                                                                   \
-       _wordcopy_fwd_dest_aligned (dst_bp, src_bp, (nbytes) / OPSIZ);        \
-      src_bp += (nbytes) & -OPSIZ;                                           \
-      dst_bp += (nbytes) & -OPSIZ;                                           \
-      (nbytes_left) = (nbytes) % OPSIZ;                                        
      \
-    } while (0)
-
 /* Copy *up to* NBYTES_TO_COPY bytes from SRC_END_PTR to DST_END_PTR,
    beginning at the words (of type op_t) right before the pointers and
    continuing towards smaller addresses.  May take advantage of that
@@ -148,3 +130,213 @@ typedef unsigned char byte;
 
 /* Threshold value for when to enter the unrolled loops.  */
 #define        OP_T_THRES      16
+
+#ifdef __ARCH_HAS_BWD_MEMCPY__
+
+/* _wordcopy_fwd_aligned -- Copy block beginning at SRCP to
+   block beginning at DSTP with LEN `op_t' words (not LEN bytes!).
+   Both SRCP and DSTP should be aligned for memory operations on `op_t's.  */
+
+static void _wordcopy_fwd_aligned (long int dstp, long int srcp, size_t len)
+{
+  op_t a0, a1;
+  a0 = a1 = 0L;
+  switch (len % 8)
+    {
+    case 2:
+      a0 = ((op_t *) srcp)[0];
+      srcp -= 6 * OPSIZ;
+      dstp -= 7 * OPSIZ;
+      len += 6;
+      goto do1;
+    case 3:
+      a1 = ((op_t *) srcp)[0];
+      srcp -= 5 * OPSIZ;
+      dstp -= 6 * OPSIZ;
+      len += 5;
+      goto do2;
+    case 4:
+      a0 = ((op_t *) srcp)[0];
+      srcp -= 4 * OPSIZ;
+      dstp -= 5 * OPSIZ;
+      len += 4;
+      goto do3;
+    case 5:
+      a1 = ((op_t *) srcp)[0];
+      srcp -= 3 * OPSIZ;
+      dstp -= 4 * OPSIZ;
+      len += 3;
+      goto do4;
+    case 6:
+      a0 = ((op_t *) srcp)[0];
+      srcp -= 2 * OPSIZ;
+      dstp -= 3 * OPSIZ;
+      len += 2;
+      goto do5;
+    case 7:
+      a1 = ((op_t *) srcp)[0];
+      srcp -= 1 * OPSIZ;
+      dstp -= 2 * OPSIZ;
+      len += 1;
+      goto do6;
+
+    case 0:
+      if (OP_T_THRES <= 3 * OPSIZ && len == 0)
+       return;
+      a0 = ((op_t *) srcp)[0];
+      srcp -= 0 * OPSIZ;
+      dstp -= 1 * OPSIZ;
+      goto do7;
+    case 1:
+      a1 = ((op_t *) srcp)[0];
+      srcp -=-1 * OPSIZ;
+      dstp -= 0 * OPSIZ;
+      len -= 1;
+      if (OP_T_THRES <= 3 * OPSIZ && len == 0)
+       goto do0;
+      goto do8;                        /* No-op.  */
+    }
+
+  do
+    {
+    do8:
+      a0 = ((op_t *) srcp)[0];
+      ((op_t *) dstp)[0] = a1;
+    do7:
+      a1 = ((op_t *) srcp)[1];
+      ((op_t *) dstp)[1] = a0;
+    do6:
+      a0 = ((op_t *) srcp)[2];
+      ((op_t *) dstp)[2] = a1;
+    do5:
+      a1 = ((op_t *) srcp)[3];
+      ((op_t *) dstp)[3] = a0;
+    do4:
+      a0 = ((op_t *) srcp)[4];
+      ((op_t *) dstp)[4] = a1;
+    do3:
+      a1 = ((op_t *) srcp)[5];
+      ((op_t *) dstp)[5] = a0;
+    do2:
+      a0 = ((op_t *) srcp)[6];
+      ((op_t *) dstp)[6] = a1;
+    do1:
+      a1 = ((op_t *) srcp)[7];
+      ((op_t *) dstp)[7] = a0;
+
+      srcp += 8 * OPSIZ;
+      dstp += 8 * OPSIZ;
+      len -= 8;
+    }
+  while (len != 0);
+
+  /* This is the right position for do0.  Please don't move
+     it into the loop.  */
+ do0:
+  ((op_t *) dstp)[0] = a1;
+}
+
+/* _wordcopy_fwd_dest_aligned -- Copy block beginning at SRCP to
+   block beginning at DSTP with LEN `op_t' words (not LEN bytes!).
+   DSTP should be aligned for memory operations on `op_t's, but SRCP must
+   *not* be aligned.  */
+
+static void _wordcopy_fwd_dest_aligned (long int dstp, long int srcp, size_t 
len)
+{
+  op_t a0, a1, a2, a3;
+  int sh_1, sh_2;
+
+  /* Calculate how to shift a word read at the memory operation
+     aligned srcp to make it aligned for copy.  */
+  a0 = a1 = a2 = a3 = 0L;
+  sh_1 = 8 * (srcp % OPSIZ);
+  sh_2 = 8 * OPSIZ - sh_1;
+ 
+  /* Make SRCP aligned by rounding it down to the beginning of the `op_t'
+     it points in the middle of.  */
+  srcp &= -OPSIZ;
+
+  switch (len % 4)
+    {
+    case 2:
+      a1 = ((op_t *) srcp)[0];
+      a2 = ((op_t *) srcp)[1];
+      srcp -= 1 * OPSIZ;
+      dstp -= 3 * OPSIZ;
+      len += 2;
+      goto do1;
+    case 3:
+      a0 = ((op_t *) srcp)[0];
+      a1 = ((op_t *) srcp)[1];
+      srcp -= 0 * OPSIZ;
+      dstp -= 2 * OPSIZ;
+      len += 1;
+      goto do2;
+    case 0:
+      if (OP_T_THRES <= 3 * OPSIZ && len == 0)
+       return;
+      a3 = ((op_t *) srcp)[0];
+      a0 = ((op_t *) srcp)[1];
+      srcp -=-1 * OPSIZ;
+      dstp -= 1 * OPSIZ;
+      len += 0;
+      goto do3;
+    case 1:
+      a2 = ((op_t *) srcp)[0];
+      a3 = ((op_t *) srcp)[1];
+      srcp -=-2 * OPSIZ;
+      dstp -= 0 * OPSIZ;
+      len -= 1;
+      if (OP_T_THRES <= 3 * OPSIZ && len == 0)
+       goto do0;
+      goto do4;                        /* No-op.  */
+    }
+
+  do
+    {
+    do4:
+      a0 = ((op_t *) srcp)[0];
+      ((op_t *) dstp)[0] = MERGE (a2, sh_1, a3, sh_2);
+    do3:
+      a1 = ((op_t *) srcp)[1];
+      ((op_t *) dstp)[1] = MERGE (a3, sh_1, a0, sh_2);
+    do2:
+      a2 = ((op_t *) srcp)[2];
+      ((op_t *) dstp)[2] = MERGE (a0, sh_1, a1, sh_2);
+    do1:
+      a3 = ((op_t *) srcp)[3];
+      ((op_t *) dstp)[3] = MERGE (a1, sh_1, a2, sh_2);
+
+      srcp += 4 * OPSIZ;
+      dstp += 4 * OPSIZ;
+      len -= 4;
+    }
+  while (len != 0);
+
+  /* This is the right position for do0.  Please don't move
+     it into the loop.  */
+ do0:
+  ((op_t *) dstp)[0] = MERGE (a2, sh_1, a3, sh_2);
+}
+
+
+/* Copy *up to* NBYTES bytes from SRC_BP to DST_BP, with
+   the assumption that DST_BP is aligned on an OPSIZ multiple.  If
+   not all bytes could be easily copied, store remaining number of bytes
+   in NBYTES_LEFT, otherwise store 0.  */
+/* extern void _wordcopy_fwd_aligned __P ((long int, long int, size_t)); */
+/* extern void _wordcopy_fwd_dest_aligned __P ((long int, long int, size_t)); 
*/
+#define WORD_COPY_FWD(dst_bp, src_bp, nbytes_left, nbytes)                   \
+  do                                                                         \
+    {                                                                        \
+      if (src_bp % OPSIZ == 0)                                               \
+       _wordcopy_fwd_aligned (dst_bp, src_bp, (nbytes) / OPSIZ);             \
+      else                                                                   \
+       _wordcopy_fwd_dest_aligned (dst_bp, src_bp, (nbytes) / OPSIZ);        \
+      src_bp += (nbytes) & -OPSIZ;                                           \
+      dst_bp += (nbytes) & -OPSIZ;                                           \
+      (nbytes_left) = (nbytes) % OPSIZ;                                        
      \
+    } while (0)
+
+#endif /* __ARCH_HAS_BWD_MEMCPY__ */
+
diff -Naupr uClibc-trunk/libc/string/generic/memcpy.c 
uClibc-trunk-st/libc/string/generic/memcpy.c
--- uClibc-trunk/libc/string/generic/memcpy.c   2006-09-19 09:43:00.000000000 
+0200
+++ uClibc-trunk-st/libc/string/generic/memcpy.c        2007-05-07 
10:28:20.217087000 +0200
@@ -25,192 +25,6 @@
 
 libc_hidden_proto(memcpy)
 
-/* _wordcopy_fwd_aligned -- Copy block beginning at SRCP to
-   block beginning at DSTP with LEN `op_t' words (not LEN bytes!).
-   Both SRCP and DSTP should be aligned for memory operations on `op_t's.  */
-
-static void _wordcopy_fwd_aligned (long int dstp, long int srcp, size_t len)
-{
-  op_t a0, a1;
-
-  switch (len % 8)
-    {
-    case 2:
-      a0 = ((op_t *) srcp)[0];
-      srcp -= 6 * OPSIZ;
-      dstp -= 7 * OPSIZ;
-      len += 6;
-      goto do1;
-    case 3:
-      a1 = ((op_t *) srcp)[0];
-      srcp -= 5 * OPSIZ;
-      dstp -= 6 * OPSIZ;
-      len += 5;
-      goto do2;
-    case 4:
-      a0 = ((op_t *) srcp)[0];
-      srcp -= 4 * OPSIZ;
-      dstp -= 5 * OPSIZ;
-      len += 4;
-      goto do3;
-    case 5:
-      a1 = ((op_t *) srcp)[0];
-      srcp -= 3 * OPSIZ;
-      dstp -= 4 * OPSIZ;
-      len += 3;
-      goto do4;
-    case 6:
-      a0 = ((op_t *) srcp)[0];
-      srcp -= 2 * OPSIZ;
-      dstp -= 3 * OPSIZ;
-      len += 2;
-      goto do5;
-    case 7:
-      a1 = ((op_t *) srcp)[0];
-      srcp -= 1 * OPSIZ;
-      dstp -= 2 * OPSIZ;
-      len += 1;
-      goto do6;
-
-    case 0:
-      if (OP_T_THRES <= 3 * OPSIZ && len == 0)
-       return;
-      a0 = ((op_t *) srcp)[0];
-      srcp -= 0 * OPSIZ;
-      dstp -= 1 * OPSIZ;
-      goto do7;
-    case 1:
-      a1 = ((op_t *) srcp)[0];
-      srcp -=-1 * OPSIZ;
-      dstp -= 0 * OPSIZ;
-      len -= 1;
-      if (OP_T_THRES <= 3 * OPSIZ && len == 0)
-       goto do0;
-      goto do8;                        /* No-op.  */
-    }
-
-  do
-    {
-    do8:
-      a0 = ((op_t *) srcp)[0];
-      ((op_t *) dstp)[0] = a1;
-    do7:
-      a1 = ((op_t *) srcp)[1];
-      ((op_t *) dstp)[1] = a0;
-    do6:
-      a0 = ((op_t *) srcp)[2];
-      ((op_t *) dstp)[2] = a1;
-    do5:
-      a1 = ((op_t *) srcp)[3];
-      ((op_t *) dstp)[3] = a0;
-    do4:
-      a0 = ((op_t *) srcp)[4];
-      ((op_t *) dstp)[4] = a1;
-    do3:
-      a1 = ((op_t *) srcp)[5];
-      ((op_t *) dstp)[5] = a0;
-    do2:
-      a0 = ((op_t *) srcp)[6];
-      ((op_t *) dstp)[6] = a1;
-    do1:
-      a1 = ((op_t *) srcp)[7];
-      ((op_t *) dstp)[7] = a0;
-
-      srcp += 8 * OPSIZ;
-      dstp += 8 * OPSIZ;
-      len -= 8;
-    }
-  while (len != 0);
-
-  /* This is the right position for do0.  Please don't move
-     it into the loop.  */
- do0:
-  ((op_t *) dstp)[0] = a1;
-}
-
-/* _wordcopy_fwd_dest_aligned -- Copy block beginning at SRCP to
-   block beginning at DSTP with LEN `op_t' words (not LEN bytes!).
-   DSTP should be aligned for memory operations on `op_t's, but SRCP must
-   *not* be aligned.  */
-
-static void _wordcopy_fwd_dest_aligned (long int dstp, long int srcp, size_t 
len)
-{
-  op_t a0, a1, a2, a3;
-  int sh_1, sh_2;
-
-  /* Calculate how to shift a word read at the memory operation
-     aligned srcp to make it aligned for copy.  */
-
-  sh_1 = 8 * (srcp % OPSIZ);
-  sh_2 = 8 * OPSIZ - sh_1;
-
-  /* Make SRCP aligned by rounding it down to the beginning of the `op_t'
-     it points in the middle of.  */
-  srcp &= -OPSIZ;
-
-  switch (len % 4)
-    {
-    case 2:
-      a1 = ((op_t *) srcp)[0];
-      a2 = ((op_t *) srcp)[1];
-      srcp -= 1 * OPSIZ;
-      dstp -= 3 * OPSIZ;
-      len += 2;
-      goto do1;
-    case 3:
-      a0 = ((op_t *) srcp)[0];
-      a1 = ((op_t *) srcp)[1];
-      srcp -= 0 * OPSIZ;
-      dstp -= 2 * OPSIZ;
-      len += 1;
-      goto do2;
-    case 0:
-      if (OP_T_THRES <= 3 * OPSIZ && len == 0)
-       return;
-      a3 = ((op_t *) srcp)[0];
-      a0 = ((op_t *) srcp)[1];
-      srcp -=-1 * OPSIZ;
-      dstp -= 1 * OPSIZ;
-      len += 0;
-      goto do3;
-    case 1:
-      a2 = ((op_t *) srcp)[0];
-      a3 = ((op_t *) srcp)[1];
-      srcp -=-2 * OPSIZ;
-      dstp -= 0 * OPSIZ;
-      len -= 1;
-      if (OP_T_THRES <= 3 * OPSIZ && len == 0)
-       goto do0;
-      goto do4;                        /* No-op.  */
-    }
-
-  do
-    {
-    do4:
-      a0 = ((op_t *) srcp)[0];
-      ((op_t *) dstp)[0] = MERGE (a2, sh_1, a3, sh_2);
-    do3:
-      a1 = ((op_t *) srcp)[1];
-      ((op_t *) dstp)[1] = MERGE (a3, sh_1, a0, sh_2);
-    do2:
-      a2 = ((op_t *) srcp)[2];
-      ((op_t *) dstp)[2] = MERGE (a0, sh_1, a1, sh_2);
-    do1:
-      a3 = ((op_t *) srcp)[3];
-      ((op_t *) dstp)[3] = MERGE (a1, sh_1, a2, sh_2);
-
-      srcp += 4 * OPSIZ;
-      dstp += 4 * OPSIZ;
-      len -= 4;
-    }
-  while (len != 0);
-
-  /* This is the right position for do0.  Please don't move
-     it into the loop.  */
- do0:
-  ((op_t *) dstp)[0] = MERGE (a2, sh_1, a3, sh_2);
-}
-
 void *memcpy (void *dstpp, const void *srcpp, size_t len)
 {
   unsigned long int dstp = (long int) dstpp;
diff -Naupr uClibc-trunk/libc/string/generic/memmove.c 
uClibc-trunk-st/libc/string/generic/memmove.c
--- uClibc-trunk/libc/string/generic/memmove.c  2006-09-19 09:43:00.000000000 
+0200
+++ uClibc-trunk-st/libc/string/generic/memmove.c       2007-05-07 
10:29:26.717396000 +0200
@@ -29,7 +29,8 @@ libc_hidden_proto(memcpy)
 
 static void _wordcopy_bwd_aligned (long int dstp, long int srcp, size_t len)
 {
-  op_t a0, a1;
+  op_t a0 = 0;
+  op_t a1 = 0;
 
   switch (len % 8)
     {
@@ -133,7 +134,10 @@ static void _wordcopy_bwd_aligned (long 
 
 static void _wordcopy_bwd_dest_aligned (long int dstp, long int srcp, size_t 
len)
 {
-  op_t a0, a1, a2, a3;
+  op_t a0 = 0;
+  op_t a1 = 0;
+  op_t a2 = 0;
+  op_t a3 = 0;
   int sh_1, sh_2;
 
   /* Calculate how to shift a word read at the memory operation
@@ -218,8 +222,8 @@ void *memmove (void *dest, const void *s
      Reduces the working set.  */
   if (dstp - srcp >= len)      /* *Unsigned* compare!  */
     {
-#if 1
-#warning REMINDER: generic-opt memmove assumes memcpy does forward copying!
+#ifndef __ARCH_HAS_BWD_MEMCPY__
+      /* generic-opt memmove assumes memcpy does forward copying! */
       memcpy(dest, src, len);
 #else
       /* Copy from the beginning to the end.  */
diff -Naupr uClibc-trunk/libc/string/sh/sh4/memcpy.S 
uClibc-trunk-st/libc/string/sh/sh4/memcpy.S
--- uClibc-trunk/libc/string/sh/sh4/memcpy.S    1970-01-01 01:00:00.000000000 
+0100
+++ uClibc-trunk-st/libc/string/sh/sh4/memcpy.S 2007-05-07 13:43:16.291529000 
+0200
@@ -0,0 +1,807 @@
+/*
+ * "memcpy" implementation of SuperH
+ *
+ * Copyright (C) 1999  Niibe Yutaka
+ * Copyright (c) 2002  STMicroelectronics Ltd
+ *   Modified from memcpy.S and micro-optimised for SH4
+ *   Stuart Menefy ([EMAIL PROTECTED])
+ *
+ */
+
+/*
+ * void *memcpy(void *dst, const void *src, size_t n);
+ *
+ * It is assumed that there is no overlap between src and dst.
+ * If there is an overlap, then the results are undefined.
+ */
+
+#include <endian.h>
+
+       !
+       !       GHIJ KLMN OPQR -->  ...G HIJK LMNO PQR.
+       !
+       
+       ! Size is 16 or greater, and may have trailing bytes
+
+       .balign 32
+.Lcase1:
+       ! Read a long word and write a long word at once
+       ! At the start of each iteration, r7 contains last long load
+       add     #-1,r5          !  79 EX
+       mov     r4,r2           !   5 MT (0 cycles latency)
+
+       mov.l   @(r0,r5),r7     !  21 LS (2 cycles latency)
+       add     #-4,r5          !  50 EX
+
+       add     #7,r2           !  79 EX
+       !
+#ifdef __LITTLE_ENDIAN__
+       ! 6 cycles, 4 bytes per iteration
+3:     mov.l   @(r0,r5),r1     !  21 LS (latency=2)    ! NMLK
+       mov     r7, r3          !   5 MT (latency=0)    ! RQPO
+       
+       cmp/hi  r2,r0           !  57 MT
+       shll16  r3              ! 103 EX
+
+       mov     r1,r6           !   5 MT (latency=0)
+       shll8   r3              ! 102 EX                ! Oxxx
+
+       shlr8   r6              ! 106 EX                ! xNML
+       mov     r1, r7          !   5 MT (latency=0)
+       
+       or      r6,r3           !  82 EX                ! ONML
+       bt/s    3b              ! 109 BR
+
+        mov.l  r3,@-r0         !  30 LS
+#else
+3:     mov.l   @(r0,r5),r1     !  21 LS (latency=2)    ! KLMN
+       mov     r7,r3           !   5 MT (latency=0)    ! OPQR
+
+       cmp/hi  r2,r0           !  57 MT
+       shlr16  r3              ! 107 EX
+
+       shlr8   r3              ! 106 EX                ! xxxO
+       mov     r1,r6           !   5 MT (latency=0)
+
+       shll8   r6              ! 102 EX                ! LMNx
+       mov     r1,r7           !   5 MT (latency=0)
+
+       or      r6,r3           !  82 EX                ! LMNO
+       bt/s    3b              ! 109 BR
+
+        mov.l  r3,@-r0         !  30 LS
+#endif
+       ! Finally, copy a byte at once, if necessary
+
+       add     #4,r5           !  50 EX
+       cmp/eq  r4,r0           !  54 MT
+
+       add     #-6,r2          !  50 EX
+       bt      9f              ! 109 BR
+
+8:     cmp/hi  r2,r0           !  57 MT
+       mov.b   @(r0,r5),r1     !  20 LS (latency=2)
+       
+       bt/s    8b              ! 109 BR
+
+        mov.b  r1,@-r0         !  29 LS
+
+9:     rts
+        nop
+
+       
+       !
+       !       GHIJ KLMN OPQR -->  .GHI JKLM NOPQ R...
+       !
+       
+       ! Size is 16 or greater, and may have trailing bytes
+
+       .balign 32
+.Lcase3:
+       ! Read a long word and write a long word at once
+       ! At the start of each iteration, r7 contains last long load
+       add     #-3,r5          ! 79 EX
+       mov     r4,r2           !  5 MT (0 cycles latency)
+
+       mov.l   @(r0,r5),r7     ! 21 LS (2 cycles latency)
+       add     #-4,r5          ! 50 EX
+
+       add     #7,r2           !  79 EX
+       !
+#ifdef __LITTLE_ENDIAN__
+       ! 6 cycles, 4 bytes per iteration
+3:     mov.l   @(r0,r5),r1     !  21 LS (latency=2)    ! NMLK
+       mov     r7, r3          !   5 MT (latency=0)    ! RQPO
+       
+       cmp/hi  r2,r0           !  57 MT
+       shll8   r3              ! 102 EX                ! QPOx
+
+       mov     r1,r6           !   5 MT (latency=0)
+       shlr16  r6              ! 107 EX
+
+       shlr8   r6              ! 106 EX                ! xxxN
+       mov     r1, r7          !   5 MT (latency=0)
+       
+       or      r6,r3           !  82 EX                ! QPON
+       bt/s    3b              ! 109 BR
+
+        mov.l  r3,@-r0         !  30 LS
+#else
+3:     mov     r1,r3           ! OPQR
+       shlr8   r3              ! xOPQ
+       mov.l   @(r0,r5),r1     ! KLMN
+       mov     r1,r6
+       shll16  r6
+       shll8   r6              ! Nxxx
+       or      r6,r3           ! NOPQ
+       cmp/hi  r2,r0
+       bt/s    3b
+        mov.l  r3,@-r0
+#endif
+
+       ! Finally, copy a byte at once, if necessary
+
+       add     #6,r5           !  50 EX
+       cmp/eq  r4,r0           !  54 MT
+
+       add     #-6,r2          !  50 EX
+       bt      9f              ! 109 BR
+
+8:     cmp/hi  r2,r0           !  57 MT
+       mov.b   @(r0,r5),r1     !  20 LS (latency=2)
+       
+       bt/s    8b              ! 109 BR
+
+        mov.b  r1,@-r0         !  29 LS
+
+9:     rts
+        nop
+       
+/* void *memcpy(void *dst, const void *src, size_t len) */
+.text
+.align 5
+.type memcpy,@function
+.globl memcpy;
+
+memcpy:
+       ! Calculate the invariants which will be used in the remainder
+       ! of the code:
+       !
+       !      r4   -->  [ ...  ] DST             [ ...  ] SRC
+       !                [ ...  ]                 [ ...  ]
+       !                  :                        :
+       !      r0   -->  [ ...  ]       r0+r5 --> [ ...  ]
+       !
+       !
+       
+       ! Short circuit the common case of src, dst and len being 32 bit aligned
+       ! and test for zero length move
+
+       mov     r6, r0          !   5 MT (0 cycle latency)
+       or      r4, r0          !  82 EX
+
+       or      r5, r0          !  82 EX
+       tst     r6, r6          !  86 MT
+
+       bt/s    99f             ! 111 BR                (zero len)
+        tst    #3, r0          !  87 MT
+
+       mov     r4, r0          !   5 MT (0 cycle latency)
+       add     r6, r0          !  49 EX
+
+       mov     #16, r1         !   6 EX
+       bt/s    .Lcase00        ! 111 BR                (aligned)
+
+        sub    r4, r5          !  75 EX
+
+       ! Arguments are not nicely long word aligned or zero len.
+       ! Check for small copies, and if so do a simple byte at a time copy.
+       !
+       ! Deciding on an exact value of 'small' is not easy, as the point at 
which
+       ! using the optimised routines become worthwhile varies (these are the
+       ! cycle counts for differnet sizes using byte-at-a-time vs. optimised):
+       !       size    byte-at-time    long    word    byte
+       !       16      42              39-40   46-50   50-55
+       !       24      58              43-44   54-58   62-67
+       !       36      82              49-50   66-70   80-85
+       ! However the penalty for getting it 'wrong' is much higher for long 
word
+       ! aligned data (and this is more common), so use a value of 16.
+       
+       cmp/gt  r6,r1           !  56 MT
+
+       add     #-1,r5          !  50 EX
+       bf/s    6f              ! 108 BR                (not small)
+
+        mov    r5, r3          !   5 MT (latency=0)
+       shlr    r6              ! 104 EX
+
+       mov.b   @(r0,r5),r1     !  20 LS (latency=2)
+       bf/s    4f              ! 111 BR
+       
+        add    #-1,r3          !  50 EX
+       tst     r6, r6          !  86 MT
+
+       bt/s    98f             ! 110 BR
+        mov.b  r1,@-r0         !  29 LS
+
+       ! 4 cycles, 2 bytes per iteration
+3:     mov.b   @(r0,r5),r1     !  20 LS (latency=2)
+
+4:     mov.b   @(r0,r3),r2     !  20 LS (latency=2)
+       dt      r6              !  67 EX
+
+       mov.b   r1,@-r0         !  29 LS
+       bf/s    3b              ! 111 BR
+
+        mov.b  r2,@-r0         !  29 LS
+98:
+       rts
+        nop
+
+99:    rts
+        mov    r4, r0
+
+       ! Size is not small, so its worthwhile looking for optimisations.
+       ! First align destination to a long word boundary.
+       !
+       ! r5 = normal value -1
+
+6:     tst     #3, r0          !  87 MT
+        mov    #3, r3          !   6 EX
+
+       bt/s    2f              ! 111 BR
+        and    r0,r3           !  78 EX
+
+       ! 3 cycles, 1 byte per iteration        
+1:     dt      r3              !  67 EX
+       mov.b   @(r0,r5),r1     !  19 LS (latency=2)
+
+       add     #-1, r6         !  79 EX
+       bf/s    1b              ! 109 BR
+
+        mov.b  r1,@-r0         !  28 LS
+
+2:     add     #1, r5          !  79 EX
+       
+       ! Now select the appropriate bulk transfer code based on relative
+       ! alignment of src and dst.
+       
+       mov     r0, r3          !   5 MT (latency=0)
+
+       mov     r5, r0          !   5 MT (latency=0)
+       tst     #1, r0          !  87 MT
+
+       bf/s    1f              ! 111 BR
+        mov    #64, r7         !   6 EX
+
+       ! bit 0 clear
+               
+       cmp/ge  r7, r6          !  55 MT
+
+       bt/s    2f              ! 111 BR
+        tst    #2, r0          !  87 MT
+
+       ! small
+       bt/s    .Lcase0
+        mov    r3, r0
+
+       bra     .Lcase2
+        nop
+
+       ! big
+2:     bt/s    .Lcase0b
+        mov    r3, r0
+
+       bra     .Lcase2b
+        nop
+       
+       ! bit 0 set
+1:     tst     #2, r0          ! 87 MT
+
+       bt/s    .Lcase1
+        mov    r3, r0
+
+       bra     .Lcase3
+        nop
+       
+
+       !
+       !       GHIJ KLMN OPQR -->  GHIJ KLMN OPQR
+       !
+
+       ! src, dst and size are all long word aligned
+       ! size is non-zero
+       
+       .balign 32
+.Lcase00:
+       mov     #64, r1         !   6 EX
+       mov     r5, r3          !   5 MT (latency=0)
+
+       cmp/gt  r6, r1          !  56 MT
+       add     #-4, r5         !  50 EX
+
+       bf      .Lcase00b       ! 108 BR                (big loop)
+       shlr2   r6              ! 105 EX
+
+       shlr    r6              ! 104 EX
+       mov.l   @(r0, r5), r1   !  21 LS (latency=2)    
+
+       bf/s    4f              ! 111 BR
+        add    #-8, r3         !  50 EX
+
+       tst     r6, r6          !  86 MT
+       bt/s    5f              ! 110 BR
+
+        mov.l  r1,@-r0         !  30 LS
+
+       ! 4 cycles, 2 long words per iteration
+3:     mov.l   @(r0, r5), r1   !  21 LS (latency=2)
+
+4:     mov.l   @(r0, r3), r2   !  21 LS (latency=2)
+       dt      r6              !  67 EX
+
+       mov.l   r1, @-r0        !  30 LS
+       bf/s    3b              ! 109 BR
+
+        mov.l  r2, @-r0        !  30 LS
+
+5:     rts
+        nop
+
+       
+       ! Size is 16 or greater and less than 64, but may have trailing bytes
+
+       .balign 32
+.Lcase0:
+       add     #-4, r5         !  50 EX
+       mov     r4, r7          !   5 MT (latency=0)
+
+       mov.l   @(r0, r5), r1   !  21 LS (latency=2)    
+       mov     #4, r2          !   6 EX
+
+       add     #11, r7         !  50 EX
+       tst     r2, r6          !  86 MT
+
+       mov     r5, r3          !   5 MT (latency=0)
+       bt/s    4f              ! 111 BR
+
+        add    #-4, r3         !  50 EX
+       mov.l   r1,@-r0         !  30 LS
+
+       ! 4 cycles, 2 long words per iteration
+3:     mov.l   @(r0, r5), r1   !  21 LS (latency=2)
+
+4:     mov.l   @(r0, r3), r2   !  21 LS (latency=2)
+       cmp/hi  r7, r0
+
+       mov.l   r1, @-r0        !  30 LS
+       bt/s    3b              ! 109 BR
+
+        mov.l  r2, @-r0        !  30 LS
+
+       ! Copy the final 0-3 bytes
+
+       add     #3,r5           !  50 EX
+       
+       cmp/eq  r0, r4          !  54 MT
+       add     #-10, r7        !  50 EX
+
+       bt      9f              ! 110 BR
+
+       ! 3 cycles, 1 byte per iteration
+1:     mov.b   @(r0,r5),r1     !  19 LS
+       cmp/hi  r7,r0           !  57 MT
+       
+       bt/s    1b              ! 111 BR
+        mov.b  r1,@-r0         !  28 LS
+
+9:     rts
+        nop
+
+       ! Size is at least 64 bytes, so will be going round the big loop at 
least once.
+       !
+       !   r2 = rounded up r4
+       !   r3 = rounded down r0
+
+       .balign 32
+.Lcase0b:
+       add     #-4, r5         !  50 EX
+
+.Lcase00b:
+       mov     r0, r3          !   5 MT (latency=0)
+       mov     #(~0x1f), r1    !   6 EX
+
+       and     r1, r3          !  78 EX
+       mov     r4, r2          !   5 MT (latency=0)
+
+       cmp/eq  r3, r0          !  54 MT
+       add     #0x1f, r2       !  50 EX
+
+       bt/s    1f              ! 110 BR
+        and    r1, r2          !  78 EX
+
+       ! copy initial words until cache line aligned
+
+       mov.l   @(r0, r5), r1   !  21 LS (latency=2)
+       tst     #4, r0          !  87 MT
+
+       mov     r5, r6          !   5 MT (latency=0)
+       add     #-4, r6         !  50 EX
+
+       bt/s    4f              ! 111 BR
+        add    #8, r3          !  50 EX
+
+       tst     #0x18, r0       !  87 MT
+       
+       bt/s    1f              ! 109 BR
+        mov.l  r1,@-r0         !  30 LS
+       
+       ! 4 cycles, 2 long words per iteration
+3:     mov.l   @(r0, r5), r1   !  21 LS (latency=2)
+
+4:     mov.l   @(r0, r6), r7   !  21 LS (latency=2)
+       cmp/eq  r3, r0          !  54 MT
+
+       mov.l   r1, @-r0        !  30 LS
+       bf/s    3b              ! 109 BR
+
+        mov.l  r7, @-r0        !  30 LS
+
+       ! Copy the cache line aligned blocks
+       !
+       ! In use: r0, r2, r4, r5
+       ! Scratch: r1, r3, r6, r7
+       !
+       ! We could do this with the four scratch registers, but if src
+       ! and dest hit the same cache line, this will thrash, so make
+       ! use of additional registers.
+       ! 
+       ! We also need r0 as a temporary (for movca), so 'undo' the invariant:
+       !   r5:  src (was r0+r5)
+       !   r1:  dest (was r0)
+       ! this can be reversed at the end, so we don't need to save any extra
+       ! state.
+       !
+1:     mov.l   r8, @-r15       !  30 LS
+       add     r0, r5          !  49 EX
+       
+       mov.l   r9, @-r15       !  30 LS
+       mov     r0, r1          !   5 MT (latency=0)
+       
+       mov.l   r10, @-r15      !  30 LS
+       add     #-0x1c, r5      !  50 EX
+       
+       mov.l   r11, @-r15      !  30 LS                        
+
+       ! 16 cycles, 32 bytes per iteration
+2:     mov.l   @(0x00,r5),r0   ! 18 LS (latency=2)
+       add     #-0x20, r1      ! 50 EX
+       mov.l   @(0x04,r5),r3   ! 18 LS (latency=2)
+       mov.l   @(0x08,r5),r6   ! 18 LS (latency=2)
+       mov.l   @(0x0c,r5),r7   ! 18 LS (latency=2)
+       mov.l   @(0x10,r5),r8   ! 18 LS (latency=2)
+       mov.l   @(0x14,r5),r9   ! 18 LS (latency=2)
+       mov.l   @(0x18,r5),r10  ! 18 LS (latency=2)
+       mov.l   @(0x1c,r5),r11  ! 18 LS (latency=2)
+       movca.l r0,@r1          ! 40 LS (latency=3-7)
+       mov.l   r3,@(0x04,r1)   ! 33 LS
+       mov.l   r6,@(0x08,r1)   ! 33 LS
+       mov.l   r7,@(0x0c,r1)   ! 33 LS
+
+       mov.l   r8,@(0x10,r1)   ! 33 LS
+       add     #-0x20, r5      ! 50 EX
+
+       mov.l   r9,@(0x14,r1)   ! 33 LS
+       cmp/eq  r2,r1           ! 54 MT
+
+       mov.l   r10,@(0x18,r1)  !  33 LS
+       bf/s    2b              ! 109 BR
+
+        mov.l  r11,@(0x1c,r1)  !  33 LS
+
+       mov     r1, r0          !   5 MT (latency=0)
+
+       mov.l   @r15+, r11      !  15 LS
+       sub     r1, r5          !  75 EX
+
+       mov.l   @r15+, r10      !  15 LS
+       cmp/eq  r4, r0          !  54 MT
+
+       bf/s    1f              ! 109 BR
+        mov.l   @r15+, r9      !  15 LS
+
+       rts
+1:      mov.l  @r15+, r8       !  15 LS
+       sub     r4, r1          !  75 EX                (len remaining)
+
+       ! number of trailing bytes is non-zero
+       !       
+       ! invariants restored (r5 already decremented by 4)
+       ! also r1=num bytes remaining
+       
+       mov     #4, r2          !   6 EX
+       mov     r4, r7          !   5 MT (latency=0)
+
+       add     #0x1c, r5       !  50 EX                (back to -4)
+       cmp/hs  r2, r1          !  58 MT
+
+       bf/s    5f              ! 108 BR
+        add     #11, r7        !  50 EX
+
+       mov.l   @(r0, r5), r6   !  21 LS (latency=2)    
+       tst     r2, r1          !  86 MT
+
+       mov     r5, r3          !   5 MT (latency=0)
+       bt/s    4f              ! 111 BR
+
+        add    #-4, r3         !  50 EX
+       cmp/hs  r2, r1          !  58 MT
+
+       bt/s    5f              ! 111 BR
+        mov.l  r6,@-r0         !  30 LS
+
+       ! 4 cycles, 2 long words per iteration
+3:     mov.l   @(r0, r5), r6   !  21 LS (latency=2)
+
+4:     mov.l   @(r0, r3), r2   !  21 LS (latency=2)
+       cmp/hi  r7, r0
+
+       mov.l   r6, @-r0        !  30 LS
+       bt/s    3b              ! 109 BR
+
+        mov.l  r2, @-r0        !  30 LS
+
+       ! Copy the final 0-3 bytes
+
+5:     cmp/eq  r0, r4          !  54 MT
+       add     #-10, r7        !  50 EX
+
+       bt      9f              ! 110 BR
+       add     #3,r5           !  50 EX
+       
+       ! 3 cycles, 1 byte per iteration
+1:     mov.b   @(r0,r5),r1     !  19 LS
+       cmp/hi  r7,r0           !  57 MT
+       
+       bt/s    1b              ! 111 BR
+        mov.b  r1,@-r0         !  28 LS
+
+9:     rts
+        nop
+
+       !
+       !       GHIJ KLMN OPQR -->  ..GH IJKL MNOP QR..
+       !
+               
+       .balign 32
+.Lcase2:
+       ! Size is 16 or greater and less then 64, but may have trailing bytes
+
+2:     mov     r5, r6          !   5 MT (latency=0)
+       add     #-2,r5          !  50 EX
+
+       mov     r4,r2           !   5 MT (latency=0)
+       add     #-4,r6          !  50 EX
+
+       add     #7,r2           !  50 EX
+3:     mov.w   @(r0,r5),r1     !  20 LS (latency=2)
+
+       mov.w   @(r0,r6),r3     !  20 LS (latency=2)
+       cmp/hi  r2,r0           !  57 MT
+
+       mov.w   r1,@-r0         !  29 LS
+       bt/s    3b              ! 111 BR
+
+        mov.w  r3,@-r0         !  29 LS
+
+       bra     10f
+        nop
+
+
+       .balign 32
+.Lcase2b:
+       ! Size is at least 64 bytes, so will be going round the big loop at 
least once.
+       !
+       !   r2 = rounded up r4
+       !   r3 = rounded down r0
+
+       mov     r0, r3          !   5 MT (latency=0)
+       mov     #(~0x1f), r1    !   6 EX
+
+       and     r1, r3          !  78 EX
+       mov     r4, r2          !   5 MT (latency=0)
+
+       cmp/eq  r3, r0          !  54 MT
+       add     #0x1f, r2       !  50 EX
+       
+       add     #-2, r5         !  50 EX
+       bt/s    1f              ! 110 BR
+        and    r1, r2          !  78 EX
+       
+       ! Copy a short word one at a time until we are cache line aligned
+       !   Normal values: r0, r2, r3, r4
+       !   Unused: r1, r6, r7
+       !   Mod: r5 (=r5-2)
+       !
+       add     #2, r3          !  50 EX
+       
+2:     mov.w   @(r0,r5),r1     !  20 LS (latency=2)
+       cmp/eq  r3,r0           !  54 MT
+               
+       bf/s    2b              ! 111 BR
+
+        mov.w  r1,@-r0         !  29 LS
+
+       ! Copy the cache line aligned blocks
+       !
+       ! In use: r0, r2, r4, r5 (=r5-2)
+       ! Scratch: r1, r3, r6, r7
+       !
+       ! We could do this with the four scratch registers, but if src
+       ! and dest hit the same cache line, this will thrash, so make
+       ! use of additional registers.
+       ! 
+       ! We also need r0 as a temporary (for movca), so 'undo' the invariant:
+       !   r5:  src (was r0+r5)
+       !   r1:  dest (was r0)
+       ! this can be reversed at the end, so we don't need to save any extra
+       ! state.
+       !
+1:     mov.l   r8, @-r15       !  30 LS
+       add     r0, r5          !  49 EX
+       
+       mov.l   r9, @-r15       !  30 LS
+       mov     r0, r1          !   5 MT (latency=0)
+       
+       mov.l   r10, @-r15      !  30 LS
+       add     #-0x1e, r5      !  50 EX
+       
+       mov.l   r11, @-r15      !  30 LS                        
+       
+       mov.l   r12, @-r15      !  30 LS                        
+
+       ! 17 cycles, 32 bytes per iteration
+#ifdef __LITTLE_ENDIAN__
+2:     mov.w   @r5+, r0        !  14 LS (latency=2)            ..JI
+       add     #-0x20, r1      !  50 EX
+
+       mov.l   @r5+, r3        !  15 LS (latency=2)            NMLK
+
+       mov.l   @r5+, r6        !  15 LS (latency=2)            RQPO
+       shll16  r0              ! 103 EX                        JI..
+
+       mov.l   @r5+, r7        !  15 LS (latency=2)
+       xtrct   r3, r0          !  48 EX                        LKJI
+
+       mov.l   @r5+, r8        !  15 LS (latency=2)
+       xtrct   r6, r3          !  48 EX                        PONM
+
+       mov.l   @r5+, r9        !  15 LS (latency=2)
+       xtrct   r7, r6          !  48 EX
+
+       mov.l   @r5+, r10       !  15 LS (latency=2)
+       xtrct   r8, r7          !  48 EX
+
+       mov.l   @r5+, r11       !  15 LS (latency=2)
+       xtrct   r9, r8          !  48 EX
+
+       mov.w   @r5+, r12       !  15 LS (latency=2)
+       xtrct   r10, r9         !  48 EX
+
+       movca.l r0,@r1          !  40 LS (latency=3-7)
+       xtrct   r11, r10        !  48 EX
+
+       mov.l   r3, @(0x04,r1)  !  33 LS
+       xtrct   r12, r11        !  48 EX
+
+       mov.l   r6, @(0x08,r1)  !  33 LS
+       
+       mov.l   r7, @(0x0c,r1)  !  33 LS
+
+       mov.l   r8, @(0x10,r1)  !  33 LS
+       add     #-0x40, r5      !  50 EX
+
+       mov.l   r9, @(0x14,r1)  !  33 LS
+       cmp/eq  r2,r1           !  54 MT
+
+       mov.l   r10, @(0x18,r1) !  33 LS
+       bf/s    2b              ! 109 BR
+
+        mov.l  r11, @(0x1c,r1) !  33 LS
+#else
+2:     mov.w   @(0x1e,r5), r0  !  17 LS (latency=2)
+       add     #-2, r5         !  50 EX
+
+       mov.l   @(0x1c,r5), r3  !  18 LS (latency=2)
+       add     #-4, r1         !  50 EX
+
+       mov.l   @(0x18,r5), r6  !  18 LS (latency=2)
+       shll16  r0              ! 103 EX
+
+       mov.l   @(0x14,r5), r7  !  18 LS (latency=2)
+       xtrct   r3, r0          !  48 EX
+
+       mov.l   @(0x10,r5), r8  !  18 LS (latency=2)
+       xtrct   r6, r3          !  48 EX
+
+       mov.l   @(0x0c,r5), r9  !  18 LS (latency=2)
+       xtrct   r7, r6          !  48 EX
+
+       mov.l   @(0x08,r5), r10 !  18 LS (latency=2)
+       xtrct   r8, r7          !  48 EX
+
+       mov.l   @(0x04,r5), r11 !  18 LS (latency=2)
+       xtrct   r9, r8          !  48 EX
+
+       mov.w   @(0x02,r5), r12 !  18 LS (latency=2)
+       xtrct   r10, r9         !  48 EX
+
+       movca.l r0,@r1          !  40 LS (latency=3-7)
+       add     #-0x1c, r1      !  50 EX
+
+       mov.l   r3, @(0x1c,r1)  !  33 LS
+       xtrct   r11, r10        !  48 EX
+
+       mov.l   r6, @(0x18,r1)  !  33 LS
+       xtrct   r12, r11        !  48 EX
+       
+       mov.l   r7, @(0x14,r1)  !  33 LS
+
+       mov.l   r8, @(0x10,r1)  !  33 LS
+       add     #-0x3e, r5      !  50 EX
+
+       mov.l   r9, @(0x0c,r1)  !  33 LS
+       cmp/eq  r2,r1           !  54 MT
+
+       mov.l   r10, @(0x08,r1) !  33 LS
+       bf/s    2b              ! 109 BR
+
+        mov.l  r11, @(0x04,r1) !  33 LS
+#endif
+
+       mov.l   @r15+, r12
+       mov     r1, r0          !   5 MT (latency=0)
+
+       mov.l   @r15+, r11      !  15 LS
+       sub     r1, r5          !  75 EX
+
+       mov.l   @r15+, r10      !  15 LS
+       cmp/eq  r4, r0          !  54 MT
+
+       bf/s    1f              ! 109 BR
+        mov.l   @r15+, r9      !  15 LS
+
+       rts
+1:      mov.l  @r15+, r8       !  15 LS
+
+       add     #0x1e, r5       !  50 EX
+       
+       ! Finish off a short word at a time
+       ! r5 must be invariant - 2
+10:    mov     r4,r2           !   5 MT (latency=0)
+       add     #1,r2           !  50 EX
+
+       cmp/hi  r2, r0          !  57 MT
+       bf/s    1f              ! 109 BR
+
+        add    #2, r2          !  50 EX
+       
+3:     mov.w   @(r0,r5),r1     !  20 LS
+       cmp/hi  r2,r0           !  57 MT
+
+       bt/s    3b              ! 109 BR
+
+        mov.w  r1,@-r0         !  29 LS
+1:
+               
+       !
+       ! Finally, copy the last byte if necessary
+       cmp/eq  r4,r0           !  54 MT
+       bt/s    9b
+        add    #1,r5
+       mov.b   @(r0,r5),r1
+       rts
+        mov.b  r1,@-r0
+
+.size memcpy,.-memcpy;
+libc_hidden_def (memcpy)
_______________________________________________
uClibc mailing list
[email protected]
http://busybox.net/cgi-bin/mailman/listinfo/uclibc

Reply via email to