Optimize memcpy.
authorKevin O'Connor <kevin@koconnor.net>
Mon, 20 Apr 2009 00:05:50 +0000 (20:05 -0400)
committerKevin O'Connor <kevin@koconnor.net>
Mon, 20 Apr 2009 00:05:50 +0000 (20:05 -0400)
Use __builtin_memcpy on small strings (gcc can inline these well).
Use 4-byte copies when applicable - this is important when copying
    option roms from slow PCI space.

src/util.c
src/util.h

index 88f134cafa8c65e1ba0362da7ac779a539fce69c..a39668b112ab052ef7b725f269f9f448c218f91e 100644 (file)
@@ -181,12 +181,24 @@ memcpy_far(u16 d_seg, void *d_far, u16 s_seg, const void *s_far, size_t len)
         : "cc", "memory");
 }
 
-void *
-memcpy(void *d1, const void *s1, size_t len)
+noinline void *
+__memcpy(void *d1, const void *s1, size_t len)
 {
-    u8 *d = (u8*)d1, *s = (u8*)s1;
-    while (len--)
-        *d++ = *s++;
+    void *d = d1;
+    if (((u32)d1 | (u32)s1 | len) & 3) {
+        // non-aligned memcpy
+        asm volatile(
+            "rep movsb (%%esi),%%es:(%%edi)\n"
+            : "+c"(len), "+S"(s1), "+D"(d)
+            : : "cc", "memory");
+        return d1;
+    }
+    // Common case - use 4-byte copy
+    len /= 4;
+    asm volatile(
+        "rep movsl (%%esi),%%es:(%%edi)\n"
+        : "+c"(len), "+S"(s1), "+D"(d)
+        : : "cc", "memory");
     return d1;
 }
 
index f260e277e456e76437f3741879e7081e8a4da460..ceb775e6a9dd48077cd704e01fd3a983bcaa40ef 100644 (file)
@@ -73,7 +73,11 @@ int memcmp(const void *s1, const void *s2, size_t n);
 size_t strlen(const char *s);
 int strcmp(const char *s1, const char *s2);
 void *memset(void *s, int c, size_t n);
-void *memcpy(void *d1, const void *s1, size_t len);
+void *__memcpy(void *d1, const void *s1, size_t len);
+#define memcpy(d1, s1, len) (                           \
+        (__builtin_constant_p(len) && (len) <= 20)      \
+        ? __builtin_memcpy((d1), (s1), (len))           \
+        :  __memcpy((d1), (s1), (len)))
 inline void memcpy_far(u16 d_seg, void *d_far
                        , u16 s_seg, const void *s_far, size_t len);
 void *memmove(void *d, const void *s, size_t len);