[PATCH v2 4/4] RISC-V: strcmp [speed optimized]: optimize mismatch logic for targets with Zb* extension support

puranikvinit <[email protected]>
Newsgroups gmane.comp.lib.newlib
Message-ID <[email protected]>
Reworks the mismatch handling to use Zbb's ctz/clz instructions for
faster byte difference detection, significantly improving performance on
Zbb-capable targets. Non-Zbb targets retain the original logic for
compatibility.

Signed-off-by: puranikvinit <[email protected]>
Reviewed-by: Christian Herber <[email protected]>
---
 newlib/libc/machine/riscv/strcmp.S | 157 +++++++++++++++++------------
 1 file changed, 94 insertions(+), 63 deletions(-)

diff --git a/newlib/libc/machine/riscv/strcmp.S b/newlib/libc/machine/riscv/strcmp.S
index 42c870c10..0b1dfc4b1 100644
--- a/newlib/libc/machine/riscv/strcmp.S
+++ b/newlib/libc/machine/riscv/strcmp.S
@@ -99,78 +99,109 @@ strcmp:
 
 .Lmismatch:
   # words don't match, but a2 has no null byte.
+  #if __riscv_zbb
+    xor a4, a2, a3              # find differing bits
 
-#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
+    # Check system endianness
+    # If little-endian, use Count Trailing Zeros (ctz)
+    # If big-endian, use Count Leading Zeros (clz)
+    # This helps identify the position of the first differing byte between a2 and a3.
 
-#if __riscv_xlen == 64
-  sll   a4, a2, 48
-  sll   a5, a3, 48
-  bne   a4, a5, .Lmismatch_upper
-  sll   a4, a2, 32
-  sll   a5, a3, 32
-  bne   a4, a5, .Lmismatch_upper
-#endif
-  sll   a4, a2, 16
-  sll   a5, a3, 16
-  bne   a4, a5, .Lmismatch_upper
-
-  srl   a4, a2, 8*SZREG-16
-  srl   a5, a3, 8*SZREG-16
-  sub   a0, a4, a5
-  and   a1, a0, 0xff
-  bnez  a1, .Lfinal_upper_diff
-  ret
+    # For example, in little-endian, least significant byte comes first.
+    # So trailing zeros help find which byte position differs.
 
-.Lmismatch_upper:
-  srl   a4, a4, 8*SZREG-16
-  srl   a5, a5, 8*SZREG-16
-  sub   a0, a4, a5
-  and   a1, a0, 0xff
-  bnez  a1, .Lfinal_upper_diff
-  ret
+    # In big-endian, most significant byte comes first, so leading zeros are used.
+    # The position will then be used to extract the differing byte.
 
-.Lfinal_upper_diff:
-  and   a4, a4, 0xff
-  and   a5, a5, 0xff
-  sub   a0, a4, a5
-  ret
+    #if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
+      ctz a5, a4
+    #else
+      clz a5, a4
+    #endif
 
-#else
+    andi a5, a5, -8             # find position of bit offset to the start of the byte where the first difference occurs
 
-#if __riscv_xlen == 64
-  srl   a4, a2, 48
-  srl   a5, a3, 48
-  bne   a4, a5, .Lmismatch_lower
-  srl   a4, a2, 32
-  srl   a5, a3, 32
-  bne   a4, a5, .Lmismatch_lower
-#endif
-  srl   a4, a2, 16
-  srl   a5, a3, 16
-  bne   a4, a5, .Lmismatch_lower
-
-  srl	a4, a2, 8
-  srl   a5, a3, 8
-  bne   a4, a5, .Lbyte_diff
-  and   a4, a2, 0xff
-  and   a5, a3, 0xff
-
-.Lbyte_diff:
-  sub	a0, a4, a5
-  ret
 
-.Lmismatch_lower:
-  srl	a2, a4, 8
-  srl   a3, a5, 8
-  bne   a2, a3, .Lfinal_lower_diff
-  and   a2, a4, 0xff
-  and   a3, a5, 0xff
+    # Shift a2 and a3 right by a5 bits to bring the target byte to the LSB, and isolate the byte of interest
+    srl a2, a2, a5
+    and a2, a2, 0xff
 
-.Lfinal_lower_diff:
-  sub	a0, a2, a3
-  ret
+    srl a3, a3, a5
+    and a3, a3, 0xff
 
-#endif
+
+    sub a0, a2, a3              # Calculate and return the difference in the isolated bytes
+    ret
+
+  #else
+    #if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
+      #if __riscv_xlen == 64
+        sll   a4, a2, 48
+        sll   a5, a3, 48
+        bne   a4, a5, .Lmismatch_upper
+        sll   a4, a2, 32
+        sll   a5, a3, 32
+        bne   a4, a5, .Lmismatch_upper
+      #endif
+      sll   a4, a2, 16
+      sll   a5, a3, 16
+      bne   a4, a5, .Lmismatch_upper
+
+      srl   a4, a2, 8*SZREG-16
+      srl   a5, a3, 8*SZREG-16
+      sub   a0, a4, a5
+      and   a1, a0, 0xff
+      bnez  a1, .Lfinal_upper_diff
+      ret
+
+      .Lmismatch_upper:
+        srl   a4, a4, 8*SZREG-16
+        srl   a5, a5, 8*SZREG-16
+        sub   a0, a4, a5
+        and   a1, a0, 0xff
+        bnez  a1, .Lfinal_upper_diff
+        ret
+
+      .Lfinal_upper_diff:
+        and   a4, a4, 0xff
+        and   a5, a5, 0xff
+        sub   a0, a4, a5
+        ret
+    #else
+      #if __riscv_xlen == 64
+        srl   a4, a2, 48
+        srl   a5, a3, 48
+        bne   a4, a5, .Lmismatch_lower
+        srl   a4, a2, 32
+        srl   a5, a3, 32
+        bne   a4, a5, .Lmismatch_lower
+      #endif
+      srl   a4, a2, 16
+      srl   a5, a3, 16
+      bne   a4, a5, .Lmismatch_lower
+
+      srl	  a4, a2, 8
+      srl   a5, a3, 8
+      bne   a4, a5, .Lbyte_diff
+      and   a4, a2, 0xff
+      and   a5, a3, 0xff
+
+      .Lbyte_diff:
+        sub	a0, a4, a5
+        ret
+
+      .Lmismatch_lower:
+        srl	  a2, a4, 8
+        srl   a3, a5, 8
+        bne   a2, a3, .Lfinal_lower_diff
+        and   a2, a4, 0xff
+        and   a3, a5, 0xff
+
+      .Lfinal_lower_diff:
+        sub	a0, a2, a3
+        ret
+    #endif
+  #endif
 	
 .Lmisaligned:
   # misaligned
-- 
2.49.0
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.