[libc-commits] [libc] [libc] Process words in inline_strcmp 8 bytes at a time (PR #214363)

Michael Jones via libc-commits libc-commits at lists.llvm.org
Mon Aug 17 10:20:40 PDT 2026


================
@@ -9,20 +9,56 @@
 #ifndef LLVM_LIBC_SRC_STRING_MEMORY_UTILS_INLINE_STRCMP_H
 #define LLVM_LIBC_SRC_STRING_MEMORY_UTILS_INLINE_STRCMP_H
 
-#include "src/__support/macros/attributes.h" // LIBC_INLINE
-#include "src/__support/macros/config.h"     // LIBC_NAMESPACE_DECL
+#include "src/__support/macros/attributes.h"   // LIBC_INLINE
+#include "src/__support/macros/config.h"       // LIBC_NAMESPACE_DECL
+#include "src/__support/macros/optimization.h" // LIBC_UNLIKELY
 #include <stddef.h>
+#include <stdint.h>
 
 namespace LIBC_NAMESPACE_DECL {
 
+constexpr int PAGE_MASK = 4095;
+constexpr int PAGE_SAFE_OFFSET = 4088;
+
+LIBC_INLINE uint64_t is_null_terminated(uint64_t v) {
+  return (v - 0x0101010101010101ULL) & ~v & 0x8080808080808080ULL;
+}
+
+LIBC_INLINE uint64_t load(const char *ptr) {
+  uint64_t val{0};
+  __builtin_memcpy(&val, ptr, sizeof(uint64_t));
+  return val;
+}
+
 template <typename Comp>
 LIBC_INLINE constexpr int inline_strcmp(const char *left, const char *right,
                                         Comp &&comp) {
-  // TODO: Look at benefits for comparing words at a time.
-  for (; *left && !comp(*left, *right); ++left, ++right)
-    ;
-  return comp(*reinterpret_cast<const unsigned char *>(left),
-              *reinterpret_cast<const unsigned char *>(right));
+  // Page boundry check fallback to generic version
+  if (LIBC_UNLIKELY((reinterpret_cast<uintptr_t>(left) & PAGE_MASK) >
+                        PAGE_SAFE_OFFSET ||
+                    (reinterpret_cast<uintptr_t>(right) & PAGE_MASK) >
+                        PAGE_SAFE_OFFSET)) {
+    for (; *left && !comp(*left, *right); ++left, ++right)
+      ;
+    return comp(static_cast<unsigned char>(*left),
+                static_cast<unsigned char>(*right));
+  }
+  while (1) {
+    uint64_t val1 = load(left);
+    uint64_t val2 = load(right);
+    uint64_t diff = val1 ^ val2;
+    uint64_t null_mask = is_null_terminated(val1);
+    // Check for character mismatch or null terminator
+    uint64_t zero_or_diff = diff | null_mask;
+    if (zero_or_diff != 0) {
+      size_t byte_pos = __builtin_ctzll(zero_or_diff) >> 3;
----------------
michaelrj-google wrote:

if we replace `>> 3` with `/ BLOCK_SIZE` the compiler should replace the division with a shift on powers of two, but it also doesn't assume the number of bits in the block size anymore. Here and below.

https://github.com/llvm/llvm-project/pull/214363


More information about the libc-commits mailing list