[PATCH 2/4] newlib: riscv: Optimize strlen()

Eric Salem <[email protected]>
Newsgroups gmane.comp.lib.newlib
Message-ID <8d889f88a619a098e9beb38d805149d58c6538cb.1742483743.git.ericsalem@gmail.com>
The RISC-V Zbb extension provides instructions optimized for bit
operations. Use them when available for the RISC-V port.

Reviewed-by: Christian Herber <[email protected]>
Signed-off-by: Eric Salem <[email protected]>
---
 newlib/libc/machine/riscv/strlen.c     | 33 +++++++++++++++--------
 newlib/libc/machine/riscv/sys/string.h | 36 +++++++++++++++++++++++++-
 2 files changed, 57 insertions(+), 12 deletions(-)

diff --git a/newlib/libc/machine/riscv/strlen.c b/newlib/libc/machine/riscv/strlen.c
index 5d314ec51a72..7e5d41617eac 100644
--- a/newlib/libc/machine/riscv/strlen.c
+++ b/newlib/libc/machine/riscv/strlen.c
@@ -31,24 +31,35 @@ size_t strlen(const char *str)
     } while ((uintxlen_t)str & (sizeof (uintxlen_t) - 1));
 
   uintxlen_t *ps = (uintxlen_t *)str;
-  while (!__libc_detect_null (*ps++))
+  uintxlen_t psval;
+
+  while (!__libc_detect_null ((psval = *ps++)))
     ;
   asm volatile ("" : "+r"(ps)); /* prevent "optimization" */
 
   str = (const char *)ps;
   size_t ret = str - start, sp = sizeof (*ps);
 
-  char c0 = str[0 - sp], c1 = str[1 - sp], c2 = str[2 - sp], c3 = str[3 - sp];
-  if (c0 == 0)             return ret + 0 - sp;
-  if (c1 == 0)             return ret + 1 - sp;
-  if (c2 == 0)             return ret + 2 - sp;
-  if (sp == 4 || c3 == 0)  return ret + 3 - sp;
+  #if __riscv_zbb
+    psval = ~__LIBC_RISCV_ZBB_ORC_B(psval);
+    psval = __LIBC_RISCV_ZBB_CNT_Z(psval);
+
+    return ret + (psval >> 3) - sp;
+  #else
+    char c0 = str[0 - sp], c1 = str[1 - sp], c2 = str[2 - sp], c3 = str[3 - sp];
+    if (c0 == 0)    return ret + 0 - sp;
+    if (c1 == 0)    return ret + 1 - sp;
+    if (c2 == 0)    return ret + 2 - sp;
+    if (c3 == 0)    return ret + 3 - sp;
 
-  c0 = str[4 - sp], c1 = str[5 - sp], c2 = str[6 - sp];
-  if (c0 == 0)             return ret + 4 - sp;
-  if (c1 == 0)             return ret + 5 - sp;
-  if (c2 == 0)             return ret + 6 - sp;
+    #if __riscv_xlen == 64
+      c0 = str[4 - sp], c1 = str[5 - sp], c2 = str[6 - sp];
+      if (c0 == 0)  return ret + 4 - sp;
+      if (c1 == 0)  return ret + 5 - sp;
+      if (c2 == 0)  return ret + 6 - sp;
+    #endif
 
-  return ret + 7 - sp;
+    return ret + 7 - sp;
+  #endif
 #endif /* not PREFER_SIZE_OVER_SPEED */
 }
diff --git a/newlib/libc/machine/riscv/sys/string.h b/newlib/libc/machine/riscv/sys/string.h
index 6a0c42a49c12..88e5dea20c6a 100644
--- a/newlib/libc/machine/riscv/sys/string.h
+++ b/newlib/libc/machine/riscv/sys/string.h
@@ -14,12 +14,46 @@
 
 #include "asm.h"
 
+#if __riscv_zbb
+  #include <riscv_bitmanip.h>
+
+  // Determine which intrinsics to use based on XLEN and endianness
+  #if __riscv_xlen == 64
+    #define __LIBC_RISCV_ZBB_ORC_B(x)       __riscv_orc_b_64(x)
+
+    #if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
+      #define __LIBC_RISCV_ZBB_CNT_Z(x)     __riscv_ctz_64(x)
+    #else
+      #define __LIBC_RISCV_ZBB_CNT_Z(x)     __riscv_clz_64(x)
+    #endif
+  #else
+    #define __LIBC_RISCV_ZBB_ORC_B(x)       __riscv_orc_b_32(x)
+
+    #if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
+      #define __LIBC_RISCV_ZBB_CNT_Z(x)     __riscv_ctz_32(x)
+    #else
+      #define __LIBC_RISCV_ZBB_CNT_Z(x)     __riscv_clz_32(x)
+    #endif
+  #endif
+#endif
+
+
 static __inline uintxlen_t __libc_detect_null(uintxlen_t w)
 {
+#if __riscv_zbb
+  /*
+    If there are any zeros in each byte of the register, all bits will
+    be unset for that byte value, otherwise, all bits will be set.
+    If the value is -1, all bits are set, meaning no null byte was found.
+  */
+  return __LIBC_RISCV_ZBB_ORC_B(w) != -1;
+#else
   uintxlen_t mask = 0x7f7f7f7f;
-  if (sizeof (w) == 8)
+  #if __riscv_xlen == 64
     mask = ((mask << 16) << 16) | mask;
+  #endif
   return ~(((w & mask) + mask) | w | mask);
+#endif
 }
 
 #endif
-- 
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.