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 + 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 *charPtr; + const uintptr_t *ptrPtr; + uintptr_t highMask = 0x80808080L; + uintptr_t lowMask = 0x01010101L; + + if (sizeof(uintptr_t) == 4) { + // do nothing + } else if (sizeof(uintptr_t) == 8) { + // setup 64 bit masks + highMask = ((highMask << 16) << 16) | highMask; + lowMask = ((lowMask << 16) << 16) | lowMask; + } 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 (charPtr = src; ((uintptr_t)charPtr & (sizeof(uintptr_t) - 1)) != 0; + ++charPtr) { + if (*charPtr == '\0') + return charPtr - src; + } + + ptrPtr = (const uintptr_t *)charPtr; + + // process sizeof(uintptr_t) bytes at a time + for (;;) { + uintptr_t value = *ptrPtr; + + if (((value - lowMask) & ~value & highMask) != 0) { + // found a zero byte + const char *cp = (const char *)ptrPtr; + + for (unsigned i = 0; i < sizeof(uintptr_t); ++i) + if (cp[i] == 0) + return cp - src + i; + } + + ptrPtr++; + } } } // namespace __llvm_libc 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,38 @@ 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, SevenBytes) { + const char *seven = "123456"; + + size_t result = __llvm_libc::strlen(seven); + ASSERT_EQ((size_t)6, result); +} + +TEST(StrLenTest, SixBytes) { + const char *six = "12345"; + + size_t result = __llvm_libc::strlen(six); + ASSERT_EQ((size_t)5, 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); +}