//===-- Strlen for generic SIMD types -------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// #ifndef LLVM_LIBC_SRC_STRING_MEMORY_UTILS_GENERIC_INLINE_STRLEN_H #define LLVM_LIBC_SRC_STRING_MEMORY_UTILS_GENERIC_INLINE_STRLEN_H #include "src/__support/CPP/bit.h" #include "src/__support/CPP/simd.h" #include "src/__support/common.h" namespace LIBC_NAMESPACE_DECL { namespace internal { // Exploit the underlying integer representation to do a variable shift. LIBC_INLINE constexpr cpp::simd_mask shift_mask(cpp::simd_mask m, size_t shift) { using bitmask_ty = cpp::internal::get_as_integer_type_t>; bitmask_ty r = cpp::bit_cast(m) >> shift; return cpp::bit_cast>(r); } LIBC_NO_SANITIZE_OOB_ACCESS LIBC_INLINE size_t string_length(const char *src) { constexpr cpp::simd null_byte = cpp::splat('\0'); size_t alignment = alignof(cpp::simd); const cpp::simd *aligned = reinterpret_cast *>( __builtin_align_down(src, alignment)); cpp::simd chars = cpp::load>(aligned, /*aligned=*/true); cpp::simd_mask mask = chars == null_byte; size_t offset = src - reinterpret_cast(aligned); if (cpp::any_of(shift_mask(mask, offset))) return cpp::find_first_set(shift_mask(mask, offset)); for (;;) { cpp::simd chars = cpp::load>(++aligned, /*aligned=*/true); cpp::simd_mask mask = chars == null_byte; if (cpp::any_of(mask)) return (reinterpret_cast(aligned) - src) + cpp::find_first_set(mask); } } } // namespace internal namespace string_length_impl = internal; } // namespace LIBC_NAMESPACE_DECL #endif // LLVM_LIBC_SRC_STRING_MEMORY_UTILS_GENERIC_INLINE_STRLEN_H