[PATCH v2 0/6] RISC-V: Optimize memmove() for speed

Kito Cheng kito.cheng@gmail.com
Thu Jul 10 01:29:26 GMT 2025


Thanks! committed to trunk after passing GCC regression :)

On Tue, Jun 17, 2025 at 11:10 PM m fally <marlene.fally@gmail.com> wrote:
>
> This is version 2 of a patch series that  optimizes the RISC-V port of
> memmove() for speed. The implementation is based on the generic port of
> the function, since that is what is currently used when compiling newlib
> for RISC-V.
>
> Changes in v2 include redirection to memcpy() if the memory areas of
> source and destination do not overlap, as well as small corrections of
> comments in the code.
>
> Link to v1: https://sourceware.org/pipermail/newlib/2025/021810.html
>
> In the stock implementation, an unroll-factor of 4 is used for
> the word-copy-loop in the case where both source and destination
> addresses are aligned on a long-boundary, and the memory areas
> overlap non-destructively or not at all. No unrolling is done in
> the destructive-overlap case. The proposed implementation uses an
> unroll-factor of 9 for both overlap-cases when both addresses are
> aligned to xlen. The unroll-factor was chosen to match memcpy() and
> speeds up the copying-process for lengths >= 9*SZREG, while almost
> not at all degrading performance for shorter lengths.
>
> If at least one address is unaligned, misaligned accesses are slow
> or prohibited, and there are >= 2*SZREG bytes left to copy, the
> proposed implementation first aligns the source address. Then, one
> whole word (or doubleword for rv64) is loaded at a time and individual
> bytes are stored back to the destination. The threshold of 2*SZREG was
> chosen in order to keep the negative effect on shorter copies caused
> by the additional overhead of the alignment operation low.
>
> If there is no overlap between the two memory regions, the function
> redirects to memcpy(). This is only done if length > SZREG in order
> to reduce overhead on very short copies.
>
> Furthermore, the function now only uses fixed-width types.
> Macros from the generic port are replaced with RISC-V-specific macros
> and static inline functions.
>
>
> The proposed implementation was tested on spike with pk for each of the
> following configurations (compiled with gcc):
>
> rv32ic -mtune=thead-c906 -mstrict-align -O3
> rv32ic -mtune=thead-c906 -mno-strict-align -O3
> rv64ic -mtune=thead-c906 -mstrict-align -O3
> rv64ic -mtune=thead-c906 -mno-strict-align -O3
>
>
> For each configuration, the following cases were considered when comparing
> the old and new implementations:
>
> both addresses are xlen-aligned
> both addresses are unaligned and have the same alignment
> source address is xlen-aligned, destination address is not
> destination address is xlen-aligned, source address is not
>
> For each configuration, 98280 tests were run. In total, there were 13027 cases
> where the new implementation was slower than the original, with a maximum
> difference of 342 retired instructions. In 324 cases the implementations were
> equally fast. In all other cases, the new implementation was faster than the
> original.
>
> Please see here for graphical comparisons between the two implementations:
> https://cloud.servus.at/s/jnHnN9gEoNMkLLc
>
> Below tables show the number of cases where the new implementation was
> faster, slower, or equally fast as the current implementation, as well as
> the max. differences in instructions retired between the implementations.
> The graphs and tables show the differences for copied lengths between
> 2 and 8191 bytes. For lengths < 2, old and new implementations were
> equally fast.
>
> --------- BENCHMARKING RESULTS ---------
>
> +--------------------------------------+
> |        rv32ic -mstrict-align         |
> +--------------------------------------+
> |      |Number   |Max. difference in   |
> |      |of cases |instructions retired |
> +------+---------+---------------------+
> |Faster|   98082 |              -35899 |
> +------+---------+---------------------+
> |Slower|     172 |                  24 |
> +------+---------+---------------------+
> |Tied  |      26 |                     |
> +------+---------+---------------------+
>
> +--------------------------------------+
> |        rv64ic -mstrict-align         |
> +--------------------------------------+
> |      |Number   |Max. difference in   |
> |      |of cases |instructions retired |
> +------+---------+---------------------+
> |Faster|   98026 |              -38382 |
> +------+---------+---------------------+
> |Slower|     229 |                 30  |
> +------+---------+---------------------+
> |Tied  |      25 |                     |
> +------+---------+---------------------+
>
> +--------------------------------------+
> |        rv32ic -mno-strict-align      |
> +--------------------------------------+
> |      |Number   |Max. difference in   |
> |      |of cases |instructions retired |
> +------+---------+---------------------+
> |Faster|   95568 |               -5231 |
> +------+---------+---------------------+
> |Slower|    2626 |                 160 |
> +------+---------+---------------------+
> |Tied  |      86 |                     |
> +------+---------+---------------------+
>
> +--------------------------------------+
> |        rv64ic -mno-strict-align      |
> +--------------------------------------+
> |      |Number   |Max. difference in   |
> |      |of cases |instructions retired |
> +------+---------+---------------------+
> |Faster|   88093 |               -2609 |
> +------+---------+---------------------+
> |Slower|   10000 |                 342 |
> +------+---------+---------------------+
> |Tied  |     187 |                     |
> +------+---------+---------------------+
>
>
> m fally (6):
>   RISC-V: memmove() speed optimized: Add implementation
>   RISC-V: memmove() speed optimized: Replace macros and use fixed-width
>     types
>   RISC-V: memmove() speed optimized: Add loop-unrolling
>   RISC-V: memmove() speed optimized: Align source address
>   RISC-V: memmove() speed optimized: Call memcpy()
>   newlib: Regenerate configuration files
>
>  newlib/Makefile.in                            |  52 ++--
>  newlib/libc/machine/riscv/Makefile.inc        |   2 +-
>  .../riscv/{memmove.S => memmove-asm.S}        |   0
>  newlib/libc/machine/riscv/memmove-stub.c      |  14 -
>  newlib/libc/machine/riscv/memmove.c           | 259 ++++++++++++++++++
>  5 files changed, 286 insertions(+), 41 deletions(-)
>  rename newlib/libc/machine/riscv/{memmove.S => memmove-asm.S} (100%)
>  delete mode 100644 newlib/libc/machine/riscv/memmove-stub.c
>  create mode 100644 newlib/libc/machine/riscv/memmove.c
>
> --
> 2.49.0
>


More information about the Newlib mailing list