mirror of
https://github.com/ipxe/ipxe
synced 2025-12-09 20:09:53 +03:00
[riscv] Speed up memmove() when copying in forwards direction
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>
This commit is contained in:
@@ -195,42 +195,13 @@ 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 ) {
|
||||
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 riscv_memmove ( void *dest, const void *src, size_t len ) {
|
||||
void *orig_dest = dest;
|
||||
unsigned long discard_data;
|
||||
|
||||
@@ -238,8 +209,14 @@ void riscv_memmove_backwards ( void *dest, const void *src, size_t len ) {
|
||||
if ( ! len )
|
||||
return;
|
||||
|
||||
/* 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 );
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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 */
|
||||
|
||||
Reference in New Issue
Block a user