This is an automated email from the ASF dual-hosted git repository. jerpelea pushed a commit to branch master in repository https://gitbox.apache.org/repos/asf/nuttx.git
commit 1948a225f8f4590d2b76a833b14649f98af41a3f Author: Justin Hammond <[email protected]> AuthorDate: Sat Aug 15 14:50:58 2026 +0800 libs/libc/machine/risc-v: Align strlcpy's destination too. The word loop walks src to a register boundary and then stores a whole register at a time to dst, but nothing establishes that dst is on a boundary too. Where the two pointers disagree about where a boundary falls, every store in that loop is misaligned. The base ISA does not require misaligned stores to be supported. Where firmware emulates them each store traps into machine mode, and where nothing emulates them the store faults, so this is not only a question of speed. Measured on a 1.4 GHz rv64 that emulates them, with a 32 KB string whose src and dst are misaligned by different amounts: generic C 410.4 MB/s this file 7.5 MB/s which is around 178 cycles per byte, flat from 512 bytes to 32 KB. Test the two pointers against each other before going wide, as arch_strcpy.S already does. Pointers that agree still reach the word loop, since walking src to a boundary walks dst to one as well; pointers that disagree take the byte path, where no single boundary serves both. After the change the misaligned case runs at 490 MB/s and the aligned rates are unchanged. The measurements come from the benchmark in apache/nuttx-apps#3706. Assisted-by: Claude:claude-opus-5 Signed-off-by: Justin Hammond <[email protected]> --- libs/libc/machine/risc-v/arch_strlcpy.S | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/libs/libc/machine/risc-v/arch_strlcpy.S b/libs/libc/machine/risc-v/arch_strlcpy.S index 6d18cf40e73..ac90a89dae5 100644 --- a/libs/libc/machine/risc-v/arch_strlcpy.S +++ b/libs/libc/machine/risc-v/arch_strlcpy.S @@ -72,7 +72,17 @@ ARCH_LIBCFUN(strlcpy): addi a2, a2, -1 /* reserve space for null terminator */ - /* Bytewise copy head: align src to SZREG boundary */ + /* The word loop below aligns src and then stores a register at a + * time to dst, so it is safe only where the two pointers agree about + * where a boundary falls. Where they do not, no single boundary + * serves both and the copy goes a byte at a time. + */ + + xor t0, a0, a1 + andi t0, t0, SZREG-1 + bnez t0, .Lcopy_tail + + /* Bytewise copy head: align src, and with it dst */ .Lcopy_head: beqz a2, .Ltruncated
