]> git.ipfire.org Git - thirdparty/ipxe.git/commitdiff
[riscv] Speed up memmove() when copying in forwards direction
authorMichael Brown <mcb30@ipxe.org>
Wed, 21 May 2025 15:12:56 +0000 (16:12 +0100)
committerMichael Brown <mcb30@ipxe.org>
Wed, 21 May 2025 15:12:56 +0000 (16:12 +0100)
Use the word-at-a-time variable-length memcpy() implementation when
performing an overlapping copy in the forwards direction, since this
is guaranteed to be safe and likely to be substantially faster than
the existing bytewise copy.

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

index 3155c3c21bdda9e0b0a50743e46a4fdd687c404c..e28dc8951e947907a18a6542c521b10dc41ef527 100644 (file)
@@ -195,51 +195,28 @@ void riscv_memset ( void *dest, size_t len, int character ) {
 }
 
 /**
- * Copy (possibly overlapping) memory region forwards
+ * Copy (possibly overlapping) memory region
  *
  * @v dest             Destination region
  * @v src              Source region
  * @v len              Length
  */
-void riscv_memmove_forwards ( void *dest, const void *src, size_t len ) {
+void riscv_memmove ( void *dest, const void *src, size_t len ) {
+       void *orig_dest = dest;
        unsigned long discard_data;
 
        /* Do nothing if length is zero */
        if ( ! len )
                return;
 
-       /* Assume memmove() is not performance-critical, and perform a
-        * bytewise copy for simplicity.
-        */
-       __asm__ __volatile__ ( "\n1:\n\t"
-                              "lb %2, (%1)\n\t"
-                              "sb %2, (%0)\n\t"
-                              "addi %1, %1, 1\n\t"
-                              "addi %0, %0, 1\n\t"
-                              "bne %0, %3, 1b\n\t"
-                              : "+r" ( dest ), "+r" ( src ),
-                                "=&r" ( discard_data )
-                              : "r" ( dest + len )
-                              : "memory" );
-}
-
-/**
- * Copy (possibly overlapping) memory region backwards
- *
- * @v dest             Destination region
- * @v src              Source region
- * @v len              Length
- */
-void riscv_memmove_backwards ( void *dest, const void *src, size_t len ) {
-       void *orig_dest = dest;
-       unsigned long discard_data;
-
-       /* Do nothing if length is zero */
-       if ( ! len )
+       /* Use memcpy() if copy direction is forwards */
+       if ( dest <= src ) {
+               memcpy ( dest, src, len );
                return;
+       }
 
        /* Assume memmove() is not performance-critical, and perform a
-        * bytewise copy for simplicity.
+        * bytewise copy backwards for simplicity.
         */
        dest += len;
        src += len;
@@ -254,19 +231,3 @@ void riscv_memmove_backwards ( void *dest, const void *src, size_t len ) {
                               : "r" ( orig_dest )
                               : "memory" );
 }
-
-/**
- * Copy (possibly overlapping) memory region
- *
- * @v dest             Destination region
- * @v src              Source region
- * @v len              Length
- */
-void riscv_memmove ( void *dest, const void *src, size_t len ) {
-
-       if ( dest <= src ) {
-               riscv_memmove_forwards ( dest, src, len );
-       } else {
-               riscv_memmove_backwards ( dest, src, len );
-       }
-}
index 3f78b351de284fcf974694b37e914ffaafd352a6..87834d91af49279dab596e28e7aeeda20e12085b 100644 (file)
@@ -12,8 +12,6 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
 extern void riscv_bzero ( void *dest, size_t len );
 extern void riscv_memset ( void *dest, size_t len, int character );
 extern void riscv_memcpy ( void *dest, const void *src, size_t len );
-extern void riscv_memmove_forwards ( void *dest, const void *src, size_t len );
-extern void riscv_memmove_backwards ( void *dest, const void *src, size_t len );
 extern void riscv_memmove ( void *dest, const void *src, size_t len );
 
 /**
@@ -68,17 +66,12 @@ static inline __attribute__ (( always_inline )) void *
 memmove ( void *dest, const void *src, size_t len ) {
        ssize_t offset = ( dest - src );
 
-       /* If required direction of copy is known at build time, then
-        * use the appropriate forwards/backwards copy directly.
+       /* If direction of copy is known to be forwards at build time,
+        * then use variable-length memcpy().
         */
-       if ( __builtin_constant_p ( offset ) ) {
-               if ( offset <= 0 ) {
-                       riscv_memmove_forwards ( dest, src, len );
-                       return dest;
-               } else {
-                       riscv_memmove_backwards ( dest, src, len );
-                       return dest;
-               }
+       if ( __builtin_constant_p ( offset ) && ( offset <= 0 ) ) {
+               riscv_memcpy ( dest, src, len );
+               return dest;
        }
 
        /* Otherwise, use ambidirectional copy */