|
8 | 8 | #ifndef LLVM_LIBC_SRC_STRING_MEMORY_UTILS_AARCH64_INLINE_STRLEN_H |
9 | 9 | #define LLVM_LIBC_SRC_STRING_MEMORY_UTILS_AARCH64_INLINE_STRLEN_H |
10 | 10 |
|
| 11 | +#include "src/__support/macros/properties/cpu_features.h" |
| 12 | + |
11 | 13 | #if defined(__ARM_NEON) |
12 | 14 | #include "src/__support/CPP/bit.h" // countr_zero |
13 | | - |
14 | 15 | #include <arm_neon.h> |
15 | 16 | #include <stddef.h> // size_t |
16 | | - |
17 | 17 | namespace LIBC_NAMESPACE_DECL { |
18 | | - |
19 | 18 | namespace neon { |
20 | 19 | [[maybe_unused]] LIBC_NO_SANITIZE_OOB_ACCESS LIBC_INLINE static size_t |
21 | 20 | string_length(const char *src) { |
@@ -45,9 +44,63 @@ string_length(const char *src) { |
45 | 44 | } |
46 | 45 | } |
47 | 46 | } // namespace neon |
| 47 | +} // namespace LIBC_NAMESPACE_DECL |
| 48 | +#endif // __ARM_NEON |
48 | 49 |
|
49 | | -namespace string_length_impl = neon; |
| 50 | +#ifdef LIBC_TARGET_CPU_HAS_SVE |
| 51 | +#include "src/__support/macros/optimization.h" |
| 52 | +#include <arm_sve.h> |
| 53 | +namespace LIBC_NAMESPACE_DECL { |
| 54 | +namespace sve { |
| 55 | +[[maybe_unused]] LIBC_INLINE static size_t string_length(const char *src) { |
| 56 | + const uint8_t *ptr = reinterpret_cast<const uint8_t *>(src); |
| 57 | + // Initialize the first-fault register to all true |
| 58 | + svsetffr(); |
| 59 | + const svbool_t all_true = svptrue_b8(); // all true predicate |
| 60 | + svbool_t cmp_zero; |
| 61 | + size_t len = 0; |
50 | 62 |
|
| 63 | + for (;;) { |
| 64 | + // Read a vector's worth of bytes, stopping on first fault. |
| 65 | + svuint8_t data = svldff1_u8(all_true, &ptr[len]); |
| 66 | + svbool_t fault_mask = svrdffr_z(all_true); |
| 67 | + bool has_no_fault = svptest_last(all_true, fault_mask); |
| 68 | + if (LIBC_LIKELY(has_no_fault)) { |
| 69 | + // First fault did not fail: the whole vector is valid. |
| 70 | + // Avoid depending on the contents of FFR beyond the branch. |
| 71 | + len += svcntb(); // speculative increment |
| 72 | + cmp_zero = svcmpeq_n_u8(all_true, data, 0); |
| 73 | + bool has_no_zero = !svptest_any(all_true, cmp_zero); |
| 74 | + if (LIBC_LIKELY(has_no_zero)) |
| 75 | + continue; |
| 76 | + len -= svcntb(); // undo speculative increment |
| 77 | + break; |
| 78 | + } else { |
| 79 | + // First fault failed: only some of the vector is valid. |
| 80 | + // Perform the comparison only on the valid bytes. |
| 81 | + cmp_zero = svcmpeq_n_u8(fault_mask, data, 0); |
| 82 | + bool has_zero = svptest_any(fault_mask, cmp_zero); |
| 83 | + if (LIBC_LIKELY(has_zero)) |
| 84 | + break; |
| 85 | + svsetffr(); |
| 86 | + len += svcntp_b8(all_true, fault_mask); |
| 87 | + continue; |
| 88 | + } |
| 89 | + } |
| 90 | + // Select the bytes before the first and count them. |
| 91 | + svbool_t before_zero = svbrkb_z(all_true, cmp_zero); |
| 92 | + len += svcntp_b8(all_true, before_zero); |
| 93 | + return len; |
| 94 | +} |
| 95 | +} // namespace sve |
| 96 | +} // namespace LIBC_NAMESPACE_DECL |
| 97 | +#endif // LIBC_TARGET_CPU_HAS_SVE |
| 98 | + |
| 99 | +namespace LIBC_NAMESPACE_DECL { |
| 100 | +#ifdef LIBC_TARGET_CPU_HAS_SVE |
| 101 | +namespace string_length_impl = sve; |
| 102 | +#elif defined(__ARM_NEON) |
| 103 | +namespace string_length_impl = neon; |
| 104 | +#endif |
51 | 105 | } // namespace LIBC_NAMESPACE_DECL |
52 | | -#endif // __ARM_NEON |
53 | 106 | #endif // LLVM_LIBC_SRC_STRING_MEMORY_UTILS_AARCH64_INLINE_STRLEN_H |
0 commit comments