This is an automated email from the ASF dual-hosted git repository.

xiaoxiang781216 pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/nuttx.git

commit ad9c9d41b09e02d87585406c7ee27eb0748d2195
Author: ganjing <[email protected]>
AuthorDate: Tue Aug 11 14:22:20 2026 +0800

    libs/libc/risc-v: Unroll memcmp with 4-word XOR|OR folding.
    
    Reduce branch overhead in the memcmp main loop by comparing four
    words per iteration: XOR each pair, OR the four differences together,
    and branch once.  On a mismatch the single-word loop locates the
    exact differing word within four words of the fault.
    
    Add a beqz guard at .Lbyte_cmp entry to handle the case where the
    4-word loop consumes all remaining bytes exactly.
    
    Measured on QEMU RV32: memcmp(128) 313 -> 271 cycles (13% faster).
    
    Assisted-by: Claude Opus 5 (1M context) <[email protected]>
    Signed-off-by: ganjing <[email protected]>
---
 libs/libc/machine/risc-v/arch_memcmp.S | 44 +++++++++++++++++++++++++++++++++-
 1 file changed, 43 insertions(+), 1 deletion(-)

diff --git a/libs/libc/machine/risc-v/arch_memcmp.S 
b/libs/libc/machine/risc-v/arch_memcmp.S
index 346022c7683..3af0a4602ca 100644
--- a/libs/libc/machine/risc-v/arch_memcmp.S
+++ b/libs/libc/machine/risc-v/arch_memcmp.S
@@ -36,7 +36,8 @@
  *
  * int memcmp(const void *s1, const void *s2, size_t n)
  *
- * Word-at-a-time comparison with byte-level mismatch detection.
+ * Word-at-a-time comparison with 4-word XOR|OR folding to reduce branch
+ * overhead in the main loop.
  
************************************************************************************/
 ARCH_LIBCFUN(memcmp):
        .cfi_sections .debug_frame
@@ -44,6 +45,8 @@ ARCH_LIBCFUN(memcmp):
 
        beqz    a2, .Lequal
 
+       /* Check if both pointers share alignment */
+
        or      t0, a0, a1
        andi    t0, t0, SZREG-1
        bnez    t0, .Lbyte_cmp
@@ -51,7 +54,44 @@ ARCH_LIBCFUN(memcmp):
        li      t0, SZREG
        bltu    a2, t0, .Lbyte_cmp
 
+       /* Need at least 4*SZREG for unrolled loop */
+
+       li      a3, 4*SZREG
+       bltu    a2, a3, .Lword_loop
+
+       /* 4-word unrolled loop: XOR each pair, OR the results.
+        * One branch per 4 words.  On difference, rewind and let
+        * the single-word loop find the exact mismatch word.
+        */
+
+.Lword4_loop:
+       REG_L   t1, 0*SZREG(a0)
+       REG_L   t2, 0*SZREG(a1)
+       REG_L   t3, 1*SZREG(a0)
+       REG_L   t4, 1*SZREG(a1)
+       xor     t1, t1, t2
+       xor     t3, t3, t4
+       or      t1, t1, t3
+
+       REG_L   t3, 2*SZREG(a0)
+       REG_L   t4, 2*SZREG(a1)
+       REG_L   t5, 3*SZREG(a0)
+       REG_L   t6, 3*SZREG(a1)
+       xor     t3, t3, t4
+       xor     t5, t5, t6
+       or      t3, t3, t5
+       or      t1, t1, t3
+
+       bnez    t1, .Lword_loop
+       addi    a0, a0, 4*SZREG
+       addi    a1, a1, 4*SZREG
+       sub     a2, a2, a3
+       bgeu    a2, a3, .Lword4_loop
+
+       /* Fall through to single-word loop for remainder */
+
 .Lword_loop:
+       bltu    a2, t0, .Lbyte_cmp
        REG_L   t1, 0(a0)
        REG_L   t2, 0(a1)
        bne     t1, t2, .Lfind_diff
@@ -62,6 +102,7 @@ ARCH_LIBCFUN(memcmp):
        beqz    a2, .Lequal
 
 .Lbyte_cmp:
+       beqz    a2, .Lequal
        lbu     t1, 0(a0)
        lbu     t2, 0(a1)
        bne     t1, t2, .Ldiff
@@ -80,6 +121,7 @@ ARCH_LIBCFUN(memcmp):
 
 .Lfind_diff:
        /* Little-endian: first differing byte is at LSB side */
+
        andi    t3, t1, 0xff
        andi    t4, t2, 0xff
        bne     t3, t4, .Lfound

Reply via email to