]> git.ipfire.org Git - thirdparty/ipxe.git/commitdiff
[libc] Reduce overall code size by externalising memmove()
authorMichael Brown <mcb30@ipxe.org>
Sun, 4 Nov 2012 22:43:59 +0000 (22:43 +0000)
committerMichael Brown <mcb30@ipxe.org>
Mon, 12 Nov 2012 16:58:49 +0000 (16:58 +0000)
Typical saving is 15-20 bytes in each file using memmove().

Signed-off-by: Michael Brown <mcb30@ipxe.org>
src/arch/x86/core/x86_string.c
src/arch/x86/include/bits/string.h

index 698dbe2e8822fddec28cae11c6b54e511ee26561..59e0eaae1523840e0b14bb287f90981d9cfcb59e 100644 (file)
@@ -35,7 +35,8 @@ FILE_LICENCE ( GPL2_OR_LATER );
  * @v len              Length
  * @ret dest           Destination address
  */
-void * __memcpy ( void *dest, const void *src, size_t len ) {
+void * __attribute__ (( noinline )) __memcpy ( void *dest, const void *src,
+                                              size_t len ) {
        void *edi = dest;
        const void *esi = src;
        int discard_ecx;
@@ -56,3 +57,50 @@ void * __memcpy ( void *dest, const void *src, size_t len ) {
                               : "memory" );
        return dest;
 }
+
+/**
+ * Copy memory area backwards
+ *
+ * @v dest             Destination address
+ * @v src              Source address
+ * @v len              Length
+ * @ret dest           Destination address
+ */
+void * __attribute__ (( noinline )) __memcpy_reverse ( void *dest,
+                                                      const void *src,
+                                                      size_t len ) {
+       void *edi = ( dest + len - 1 );
+       const void *esi = ( src + len - 1 );
+       int discard_ecx;
+
+       /* Assume memmove() is not performance-critical, and perform a
+        * bytewise copy for simplicity.
+        */
+       __asm__ __volatile__ ( "std\n\t"
+                              "rep movsb\n\t"
+                              "cld\n\t"
+                              : "=&D" ( edi ), "=&S" ( esi ),
+                                "=&c" ( discard_ecx )
+                              : "0" ( edi ), "1" ( esi ),
+                                "2" ( len )
+                              : "memory" );
+       return dest;
+}
+
+
+/**
+ * Copy (possibly overlapping) memory area
+ *
+ * @v dest             Destination address
+ * @v src              Source address
+ * @v len              Length
+ * @ret dest           Destination address
+ */
+void * __memmove ( void *dest, const void *src, size_t len ) {
+
+       if ( dest <= src ) {
+               return __memcpy ( dest, src, len );
+       } else {
+               return __memcpy_reverse ( dest, src, len );
+       }
+}
index d9ebe30604635fb82f0bd27834d9f83316e5ec9b..e5850ed9323f3df864ee00468f5381c94e7a7e1c 100644 (file)
@@ -26,6 +26,7 @@ FILE_LICENCE ( PUBLIC_DOMAIN );
 #define __HAVE_ARCH_MEMCPY
 
 extern void * __memcpy ( void *dest, const void *src, size_t len );
+extern void * __memcpy_reverse ( void *dest, const void *src, size_t len );
 
 static inline __attribute__ (( always_inline )) void *
 __constant_memcpy ( void *dest, const void *src, size_t len ) {
@@ -144,29 +145,30 @@ __constant_memcpy ( void *dest, const void *src, size_t len ) {
          __memcpy ( (dest), (src), (len) ) )
 
 #define __HAVE_ARCH_MEMMOVE
-static inline void * memmove(void * dest,const void * src, size_t n)
-{
-int d0, d1, d2;
-if (dest<src)
-__asm__ __volatile__(
-       "cld\n\t"
-       "rep\n\t"
-       "movsb"
-       : "=&c" (d0), "=&S" (d1), "=&D" (d2)
-       :"0" (n),"1" (src),"2" (dest)
-       : "memory");
-else
-__asm__ __volatile__(
-       "std\n\t"
-       "rep\n\t"
-       "movsb\n\t"
-       "cld"
-       : "=&c" (d0), "=&S" (d1), "=&D" (d2)
-       :"0" (n),
-        "1" (n-1+(const char *)src),
-        "2" (n-1+(char *)dest)
-       :"memory");
-return dest;
+
+extern void * __memmove ( void *dest, const void *src, size_t len );
+
+/**
+ * Copy (possibly overlapping) memory area
+ *
+ * @v dest             Destination address
+ * @v src              Source address
+ * @v len              Length
+ * @ret dest           Destination address
+ */
+static inline __attribute__ (( always_inline )) void *
+memmove ( void *dest, const void *src, size_t len ) {
+       ssize_t offset = ( dest - src );
+
+       if ( __builtin_constant_p ( offset ) ) {
+               if ( offset <= 0 ) {
+                       return memcpy ( dest, src, len );
+               } else {
+                       return __memcpy_reverse ( dest, src, len );
+               }
+       } else {
+               return __memmove ( dest, src, len );
+       }
 }
 
 #define __HAVE_ARCH_MEMSET