nuttx/libs/libc/machine
Justin Hammond 0790b52e64 libs/libc/machine/risc-v: Compare a register at a time on equal offsets.
memcmp, strncmp and strcmp reach their word loops only when both pointers
are already on a register boundary:

  or    t0, a0, a1
  andi  t0, t0, SZREG-1

That asks more than the loops need.  They load from the two pointers at
the same boundary, so what matters is that the two agree about where a
boundary falls, not that either is already on one.  A pair offset by the
same amount can be walked up to the boundary a byte at a time and
compared a register at a time from there.

The union also holds far less often than the difference.  For arbitrary
pointers on RV64 it is true about one time in 64 against one in eight,
and the case it rejects, two strings carved out of the same buffer, is
the common one.

Test the difference of the pointers, and walk to the boundary first.
arch_strcpy.S and arch_memcpy.S already do this.  Keeping every access
aligned is not only faster here: the base ISA does not require misaligned
loads and stores to be supported at all, so a routine in a machine
directory cannot assume one will work, whatever it costs.

Measured on a 1.4 GHz rv64, source and destination misaligned by one:

                    before   after
  memcmp 32K          34.4   458.0 MB/s
  strncmp 32K         32.4   253.0 MB/s
  strcmp 32K          41.0   280.0 MB/s

Each of those was the rate of the byte loop the word loop was meant to
replace.  Pointers that genuinely disagree still take the byte loop, 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 <justin@dynam.ac>
2026-08-17 12:24:06 +02:00
..
arm arm: memcpy: add NEON paths for aligned copies 2026-05-09 09:46:43 +08:00
arm64 include/debug.h: Move to include/nuttx/debug.h 2026-04-07 07:50:06 -03:00
mips arch/mips: Add support for loadable ELF modules 2026-08-11 09:46:46 -03:00
renesas libc/machine/renesas: Move all source files out of gnu folder 2025-06-30 09:56:27 +08:00
risc-v libs/libc/machine/risc-v: Compare a register at a time on equal offsets. 2026-08-17 12:24:06 +02:00
sim include/debug.h: Move to include/nuttx/debug.h 2026-04-07 07:50:06 -03:00
sparc include/debug.h: Move to include/nuttx/debug.h 2026-04-07 07:50:06 -03:00
tricore arch/tricore: Full implementation of setjmp and longjmp. 2026-05-22 00:38:02 +08:00
x86 include/debug.h: Move to include/nuttx/debug.h 2026-04-07 07:50:06 -03:00
x86_64 include/debug.h: Move to include/nuttx/debug.h 2026-04-07 07:50:06 -03:00
xtensa include/debug.h: Move to include/nuttx/debug.h 2026-04-07 07:50:06 -03:00
arch_atomic.c sched/spin_lock: rename raw_spin_lock to spin_lock_notrace 2025-02-13 20:48:15 +08:00
arch_libc.c string:use builtin function to optimize libc function 2025-12-20 10:38:53 +08:00
CMakeLists.txt libc/machine/CMakeLists: should alaways build arch_atomic.c 2024-11-03 02:33:03 +08:00
Kconfig arch:use ARCH_64BIT to mark arch is support 64bit 2025-12-18 22:05:12 +08:00
Make.defs arch/mips: Add support for loadable ELF modules 2026-08-11 09:46:46 -03:00