[libc-commits] [PATCH] D77949: [libc] Add SIMD strlen implementation .

Thorsten via Phabricator via libc-commits libc-commits at lists.llvm.org
Sat Apr 11 10:07:52 PDT 2020


tschuett created this revision.
tschuett added reviewers: sivachandra, abrachet, PaulkaToast.
tschuett added a project: libc-project.

It tries to improve the performance of strlen by processing multiple bytes at a time.

Bear with me. This is my first contribution and I have no commit access.


https://reviews.llvm.org/D77949

Files:
  libc/src/string/strlen.cpp
  libc/test/src/string/strlen_test.cpp


Index: libc/test/src/string/strlen_test.cpp
===================================================================
--- libc/test/src/string/strlen_test.cpp
+++ libc/test/src/string/strlen_test.cpp
@@ -22,3 +22,24 @@
   size_t result = __llvm_libc::strlen(any);
   ASSERT_EQ((size_t)12, result);
 }
+
+TEST(StrLenTest, EightBytes) {
+  const char *eight = "1234567";
+
+  size_t result = __llvm_libc::strlen(eight);
+  ASSERT_EQ((size_t)7, result);
+}
+
+TEST(StrLenTest, FourBytes) {
+  const char *four = "123";
+
+  size_t result = __llvm_libc::strlen(four);
+  ASSERT_EQ((size_t)3, result);
+}
+
+TEST(StrLenTest, TwoBytes) {
+  const char *two = "1";
+
+  size_t result = __llvm_libc::strlen(two);
+  ASSERT_EQ((size_t)1, result);
+}
Index: libc/src/string/strlen.cpp
===================================================================
--- libc/src/string/strlen.cpp
+++ libc/src/string/strlen.cpp
@@ -10,15 +10,57 @@
 
 #include "src/__support/common.h"
 
+#include <stdint.h>
+
 namespace __llvm_libc {
 
-// TODO: investigate the performance of this function.
-// There might be potential for compiler optimization.
+// For LLP64, i.e., Windows, pointers are 64 bit and long is only 32 bit
+// Thus, this implementation uses uintptr_t instead of long
+
 size_t LLVM_LIBC_ENTRYPOINT(strlen)(const char *src) {
-  const char *end = src;
-  while (*end != '\0')
-    ++end;
-  return end - src;
+  const char *char_ptr;
+  const uintptr_t *ptr_ptr;
+  uintptr_t high_mask = 0x80808080L;
+  uintptr_t low_mask = 0x01010101L;
+
+  if (sizeof(uintptr_t) == 4) {
+    // do nothing
+  } else if (sizeof(uintptr_t) == 8) {
+    // setup 64 bit masks
+    high_mask = ((high_mask << 16) << 16) | high_mask;
+    low_mask = ((low_mask << 16) << 16) | low_mask;
+  } else {
+    // fallback to slow path
+    const char *end = src;
+    while (*end != '\0')
+      ++end;
+    return end - src;
+  }
+
+  // align char_ptr to multiple of sizeof(uintptr_t)
+  for (char_ptr = src; ((uintptr_t)char_ptr & (sizeof(uintptr_t) - 1)) != 0;
+       ++char_ptr) {
+    if (*char_ptr == '\0')
+      return char_ptr - src;
+  }
+
+  ptr_ptr = (const uintptr_t *)char_ptr;
+
+  // process sizeof(uintptr_t) bytes at a time
+  for (;;) {
+    uintptr_t value = *ptr_ptr;
+
+    if (((value - low_mask) & ~value & high_mask) != 0) {
+      // found a zero byte
+      const char *cp = (const char *)ptr_ptr;
+
+      for (unsigned i = 0; i < sizeof(uintptr_t); ++i)
+        if (cp[i] == 0)
+          return cp - src + i;
+    }
+
+    ptr_ptr++;
+  }
 }
 
 } // namespace __llvm_libc


-------------- next part --------------
A non-text attachment was scrubbed...
Name: D77949.256780.patch
Type: text/x-patch
Size: 2567 bytes
Desc: not available
URL: <http://lists.llvm.org/pipermail/libc-commits/attachments/20200411/7bdc0e6a/attachment-0001.bin>


More information about the libc-commits mailing list