blob: a68ec02bf2fe4ae0a3bf291fb75a6eb1d246651b [file] [log] [blame] [edit]
// 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_