blob: 68fba2afb3a5cc477f012dfcc8af5e759835cbc2 [file] [log] [blame]
//===-- 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<char> shift_mask(cpp::simd_mask<char> m,
size_t shift) {
using bitmask_ty = cpp::internal::get_as_integer_type_t<cpp::simd_mask<char>>;
bitmask_ty r = cpp::bit_cast<bitmask_ty>(m) >> shift;
return cpp::bit_cast<cpp::simd_mask<char>>(r);
}
[[clang::no_sanitize("address")]] LIBC_INLINE size_t
string_length(const char *src) {
constexpr cpp::simd<char> null_byte = cpp::splat('\0');
size_t alignment = alignof(cpp::simd<char>);
const cpp::simd<char> *aligned = reinterpret_cast<const cpp::simd<char> *>(
__builtin_align_down(src, alignment));
cpp::simd<char> chars = cpp::load_aligned<cpp::simd<char>>(aligned);
cpp::simd_mask<char> mask = cpp::simd_cast<bool>(chars == null_byte);
size_t offset = src - reinterpret_cast<const char *>(aligned);
if (cpp::any_of(shift_mask(mask, offset)))
return cpp::find_first_set(shift_mask(mask, offset));
for (;;) {
cpp::simd<char> chars = cpp::load_aligned<cpp::simd<char>>(++aligned);
cpp::simd_mask<char> mask = cpp::simd_cast<bool>(chars == null_byte);
if (cpp::any_of(mask))
return (reinterpret_cast<const char *>(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