| // Copyright 2022 The Fuchsia Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #ifndef LIB_UTF_UTILS_INTERNAL_ARM_NEON_H_ |
| #define LIB_UTF_UTILS_INTERNAL_ARM_NEON_H_ |
| |
| #ifdef __aarch64__ |
| |
| #include <arm_neon.h> |
| #include <lib/stdcompat/bit.h> |
| |
| #include <array> |
| #include <cstddef> |
| #include <cstdint> |
| |
| namespace utfutils { |
| namespace internal { |
| namespace arm { |
| |
| class Neon { |
| public: |
| class Vector { |
| public: |
| using Underlying = uint8x16_t; |
| |
| static Vector LoadFromArray(const void *ptr) { |
| return Vector(vld1q_u8(static_cast<const uint8_t *>(ptr))); |
| } |
| |
| static Vector Fill(uint8_t val) { return Vector(val); } |
| |
| static Vector Set32(const std::array<uint8_t, 32> &vals) { return Vector(vld1q_u8(&vals[16])); } |
| |
| static Vector SetRepeat16(const std::array<uint8_t, 16> &vals) { |
| return Vector(vld1q_u8(vals.data())); |
| } |
| |
| Vector() = default; |
| |
| explicit Vector(Underlying vec) : vec_(vec) {} |
| |
| explicit Vector(uint8_t val) : vec_(vdupq_n_u8(val)) {} |
| |
| Vector(const Vector &) = default; |
| Vector &operator=(const Vector &) = default; |
| |
| // NOLINTNEXTLINE(google-explicit-constructor) |
| operator Underlying() const { return vec_; } |
| |
| const Underlying &operator*() const { return value(); } |
| |
| Underlying operator*() { return value(); } |
| |
| friend Vector operator|(const Vector &a, const Vector &b) { return Vector(vorrq_u8(*a, *b)); } |
| |
| Vector &operator|=(const Vector &other) { |
| *this = *this | other; |
| return *this; |
| } |
| |
| friend Vector operator&(const Vector &a, const Vector &b) { return Vector(vandq_u8(*a, *b)); } |
| |
| friend Vector operator^(const Vector &a, const Vector &b) { return Vector(veorq_u8(*a, *b)); } |
| |
| bool IsAllZero() const { return vmaxvq_u8(*this) == 0; } |
| |
| bool IsAscii() const { return vmaxvq_u8(*this) < 0b10000000; } |
| |
| Underlying &value() { return vec_; } |
| |
| const Underlying &value() const { return vec_; } |
| |
| Vector UnsignedGt(const Vector &other) const { return Vector(vcgtq_u8(*this, *other)); } |
| |
| Vector SaturatingSub(const Vector &subtrahend) const { |
| return Vector(vqsubq_u8(*this, *subtrahend)); |
| } |
| |
| Vector Shr4() const { return Vector(vshrq_n_u8(*this, 4)); } |
| |
| template <size_t N> |
| Vector Prev(const Vector &prev) const { |
| static_assert(N <= 16, "Previous shift must be <= 16"); |
| |
| return Vector(vextq_u8(*prev, *this, static_cast<int>(size_t{16} - N))); |
| } |
| |
| Vector Lookup16(const std::array<uint8_t, 16> &table) const { |
| return Vector(vqtbl1q_u8(Vector::SetRepeat16(table), *this)); |
| } |
| |
| void StoreToArray(void *ptr) const { vst1q_u8(static_cast<uint8_t *>(ptr), *this); } |
| |
| private: |
| Underlying vec_; |
| }; |
| |
| static_assert(sizeof(Vector) == sizeof(Vector::Underlying), |
| "Vector and underlying type must be the same size"); |
| |
| static void Prefetch(const char *ptr) {} |
| |
| static constexpr size_t VectorSize() { return sizeof(Vector); } |
| |
| static Vector Check2Or3Continuation(const Vector &prev2, const Vector &prev3) { |
| Vector is_third_byte = prev2.UnsignedGt(Vector::Fill(0b11011111)); |
| Vector is_fourth_byte = prev3.UnsignedGt(Vector::Fill(0b11101111)); |
| |
| return is_third_byte | is_fourth_byte; |
| } |
| }; |
| |
| } // namespace arm |
| } // namespace internal |
| } // namespace utfutils |
| |
| #endif |
| |
| #endif // LIB_UTF_UTILS_INTERNAL_ARM_NEON_H_ |