#![allow(dead_code)]
#![allow(clippy::undocumented_unsafe_blocks)]
#![cfg_attr(not(feature = "unchecked"), forbid(unsafe_code))]
use zerocopy::{FromBytes, Immutable, IntoBytes, KnownLayout, Ref};
#[inline(always)]
pub fn row_slice(buf: &[u8], offset: usize, len: usize) -> &[u8] {
&buf[offset..offset + len]
}
#[inline(always)]
pub fn row_slice_mut(buf: &mut [u8], offset: usize, len: usize) -> &mut [u8] {
&mut buf[offset..offset + len]
}
#[inline(always)]
pub fn row_slice_u16(buf: &[u16], offset: usize, len: usize) -> &[u16] {
&buf[offset..offset + len]
}
#[inline(always)]
pub fn row_slice_u16_mut(buf: &mut [u16], offset: usize, len: usize) -> &mut [u16] {
&mut buf[offset..offset + len]
}
#[inline(always)]
pub fn idx<T>(buf: &[T], i: usize) -> &T {
&buf[i]
}
#[inline(always)]
pub fn idx_mut<T>(buf: &mut [T], i: usize) -> &mut T {
&mut buf[i]
}
pub trait SliceExt<T> {
fn at(&self, i: usize) -> &T;
fn at_mut(&mut self, i: usize) -> &mut T;
fn sub(&self, start: usize, len: usize) -> &[T];
fn sub_mut(&mut self, start: usize, len: usize) -> &mut [T];
}
impl<T> SliceExt<T> for [T] {
#[inline(always)]
fn at(&self, i: usize) -> &T {
&self[i]
}
#[inline(always)]
fn at_mut(&mut self, i: usize) -> &mut T {
&mut self[i]
}
#[inline(always)]
fn sub(&self, start: usize, len: usize) -> &[T] {
&self[start..start + len]
}
#[inline(always)]
fn sub_mut(&mut self, start: usize, len: usize) -> &mut [T] {
&mut self[start..start + len]
}
}
pub struct FlexSlice<'a, T>(pub &'a [T]);
pub struct FlexSliceMut<'a, T>(pub &'a mut [T]);
impl<'a, T> FlexSlice<'a, T> {
#[inline(always)]
pub fn len(&self) -> usize {
self.0.len()
}
#[inline(always)]
pub fn is_empty(&self) -> bool {
self.0.is_empty()
}
#[inline(always)]
pub fn as_slice(&self) -> &'a [T] {
self.0
}
#[inline(always)]
pub fn iter(&self) -> core::slice::Iter<'a, T> {
self.0.iter()
}
}
impl<'a, T> FlexSliceMut<'a, T> {
#[inline(always)]
pub fn len(&self) -> usize {
self.0.len()
}
#[inline(always)]
pub fn is_empty(&self) -> bool {
self.0.is_empty()
}
#[inline(always)]
pub fn as_slice(&self) -> &[T] {
self.0
}
#[inline(always)]
pub fn as_mut_slice(&mut self) -> &mut [T] {
self.0
}
#[inline(always)]
pub fn iter(&self) -> core::slice::Iter<'_, T> {
self.0.iter()
}
#[inline(always)]
pub fn iter_mut(&mut self) -> core::slice::IterMut<'_, T> {
self.0.iter_mut()
}
#[inline(always)]
pub fn flex(&self) -> FlexSlice<'_, T> {
FlexSlice(self.0)
}
}
impl<'a, T> core::ops::Deref for FlexSlice<'a, T> {
type Target = [T];
#[inline(always)]
fn deref(&self) -> &[T] {
self.0
}
}
impl<'a, T> core::ops::Deref for FlexSliceMut<'a, T> {
type Target = [T];
#[inline(always)]
fn deref(&self) -> &[T] {
self.0
}
}
impl<'a, T> core::ops::DerefMut for FlexSliceMut<'a, T> {
#[inline(always)]
fn deref_mut(&mut self) -> &mut [T] {
self.0
}
}
impl<T> core::ops::Index<usize> for FlexSlice<'_, T> {
type Output = T;
#[inline(always)]
fn index(&self, i: usize) -> &T {
&self.0[i]
}
}
impl<T> core::ops::Index<core::ops::Range<usize>> for FlexSlice<'_, T> {
type Output = [T];
#[inline(always)]
fn index(&self, r: core::ops::Range<usize>) -> &[T] {
&self.0[r]
}
}
impl<T> core::ops::Index<core::ops::RangeFrom<usize>> for FlexSlice<'_, T> {
type Output = [T];
#[inline(always)]
fn index(&self, r: core::ops::RangeFrom<usize>) -> &[T] {
&self.0[r]
}
}
impl<T> core::ops::Index<core::ops::RangeTo<usize>> for FlexSlice<'_, T> {
type Output = [T];
#[inline(always)]
fn index(&self, r: core::ops::RangeTo<usize>) -> &[T] {
&self.0[r]
}
}
impl<T> core::ops::Index<core::ops::RangeFull> for FlexSlice<'_, T> {
type Output = [T];
#[inline(always)]
fn index(&self, _r: core::ops::RangeFull) -> &[T] {
self.0
}
}
impl<T> core::ops::Index<usize> for FlexSliceMut<'_, T> {
type Output = T;
#[inline(always)]
fn index(&self, i: usize) -> &T {
&self.0[i]
}
}
impl<T> core::ops::IndexMut<usize> for FlexSliceMut<'_, T> {
#[inline(always)]
fn index_mut(&mut self, i: usize) -> &mut T {
&mut self.0[i]
}
}
impl<T> core::ops::Index<core::ops::Range<usize>> for FlexSliceMut<'_, T> {
type Output = [T];
#[inline(always)]
fn index(&self, r: core::ops::Range<usize>) -> &[T] {
&self.0[r]
}
}
impl<T> core::ops::IndexMut<core::ops::Range<usize>> for FlexSliceMut<'_, T> {
#[inline(always)]
fn index_mut(&mut self, r: core::ops::Range<usize>) -> &mut [T] {
&mut self.0[r]
}
}
impl<T> core::ops::Index<core::ops::RangeFrom<usize>> for FlexSliceMut<'_, T> {
type Output = [T];
#[inline(always)]
fn index(&self, r: core::ops::RangeFrom<usize>) -> &[T] {
&self.0[r]
}
}
impl<T> core::ops::IndexMut<core::ops::RangeFrom<usize>> for FlexSliceMut<'_, T> {
#[inline(always)]
fn index_mut(&mut self, r: core::ops::RangeFrom<usize>) -> &mut [T] {
&mut self.0[r]
}
}
impl<T> core::ops::Index<core::ops::RangeTo<usize>> for FlexSliceMut<'_, T> {
type Output = [T];
#[inline(always)]
fn index(&self, r: core::ops::RangeTo<usize>) -> &[T] {
&self.0[r]
}
}
impl<T> core::ops::IndexMut<core::ops::RangeTo<usize>> for FlexSliceMut<'_, T> {
#[inline(always)]
fn index_mut(&mut self, r: core::ops::RangeTo<usize>) -> &mut [T] {
&mut self.0[r]
}
}
impl<T> core::ops::Index<core::ops::RangeFull> for FlexSliceMut<'_, T> {
type Output = [T];
#[inline(always)]
fn index(&self, _r: core::ops::RangeFull) -> &[T] {
self.0
}
}
impl<T> core::ops::IndexMut<core::ops::RangeFull> for FlexSliceMut<'_, T> {
#[inline(always)]
fn index_mut(&mut self, _r: core::ops::RangeFull) -> &mut [T] {
self.0
}
}
pub trait Flex<T> {
fn flex(&self) -> FlexSlice<'_, T>;
fn flex_mut(&mut self) -> FlexSliceMut<'_, T>;
}
impl<T> Flex<T> for [T] {
#[inline(always)]
fn flex(&self) -> FlexSlice<'_, T> {
FlexSlice(self)
}
#[inline(always)]
fn flex_mut(&mut self) -> FlexSliceMut<'_, T> {
FlexSliceMut(self)
}
}
#[inline(always)]
pub fn reinterpret_slice<Src: IntoBytes + Immutable, Dst: FromBytes + KnownLayout + Immutable>(
src: &[Src],
) -> Option<&[Dst]> {
let bytes = src.as_bytes();
let r: Ref<&[u8], [Dst]> = Ref::from_bytes(bytes).ok()?;
Some(Ref::into_ref(r))
}
#[inline(always)]
pub fn reinterpret_slice_mut<
Src: IntoBytes + FromBytes + KnownLayout,
Dst: IntoBytes + FromBytes + KnownLayout,
>(
src: &mut [Src],
) -> Option<&mut [Dst]> {
let bytes = src.as_mut_bytes();
<[Dst]>::mut_from_bytes(bytes).ok()
}
#[inline(always)]
pub fn reinterpret_ref<Src: IntoBytes + Immutable, Dst: FromBytes + KnownLayout + Immutable>(
src: &Src,
) -> Option<&Dst> {
let bytes = src.as_bytes();
let r: Ref<&[u8], Dst> = Ref::from_bytes(bytes).ok()?;
Some(Ref::into_ref(r))
}
#[cfg(feature = "asm")]
#[inline(always)]
pub unsafe fn strided_slice_from_ptr<'a, T>(
ptr: *mut T,
stride: isize,
w: usize,
h: usize,
) -> (&'a mut [T], usize) {
if h == 0 {
return (&mut [], 0);
}
let abs_stride = stride.unsigned_abs();
let total = (h - 1) * abs_stride + w;
if stride >= 0 {
(std::slice::from_raw_parts_mut(ptr, total), 0)
} else {
let base = (h - 1) * abs_stride;
let start = ptr.offset(-((base) as isize));
(std::slice::from_raw_parts_mut(start, total), base)
}
}
#[cfg(target_arch = "x86_64")]
macro_rules! loadu_256 {
($src:expr) => {{
#[cfg(not(feature = "unchecked"))]
{
safe_unaligned_simd::x86_64::_mm256_loadu_si256($src)
}
#[cfg(feature = "unchecked")]
{
#[allow(unsafe_code)]
unsafe {
core::arch::x86_64::_mm256_loadu_si256(core::ptr::from_ref($src).cast())
}
}
}};
($slice:expr, $T:ty) => {{
#[cfg(not(feature = "unchecked"))]
{
safe_unaligned_simd::x86_64::_mm256_loadu_si256::<$T>(($slice).try_into().unwrap())
}
#[cfg(feature = "unchecked")]
{
let __s = $slice;
debug_assert!(core::mem::size_of_val(__s) >= 32);
#[allow(unsafe_code)]
unsafe {
core::arch::x86_64::_mm256_loadu_si256(__s.as_ptr() as *const _)
}
}
}};
}
#[cfg(target_arch = "x86_64")]
pub(crate) use loadu_256;
#[cfg(target_arch = "x86_64")]
macro_rules! storeu_256 {
($dst:expr, $val:expr) => {{
#[cfg(not(feature = "unchecked"))]
{
safe_unaligned_simd::x86_64::_mm256_storeu_si256($dst, $val)
}
#[cfg(feature = "unchecked")]
{
#[allow(unsafe_code)]
unsafe {
core::arch::x86_64::_mm256_storeu_si256(core::ptr::from_mut($dst).cast(), $val)
}
}
}};
($slice:expr, $T:ty, $val:expr) => {{
#[cfg(not(feature = "unchecked"))]
{
safe_unaligned_simd::x86_64::_mm256_storeu_si256::<$T>(
($slice).try_into().unwrap(),
$val,
)
}
#[cfg(feature = "unchecked")]
{
let __s = $slice;
debug_assert!(core::mem::size_of_val(__s) >= 32);
#[allow(unsafe_code)]
unsafe {
core::arch::x86_64::_mm256_storeu_si256(__s.as_mut_ptr() as *mut _, $val)
}
}
}};
}
#[cfg(target_arch = "x86_64")]
pub(crate) use storeu_256;
#[cfg(target_arch = "x86_64")]
macro_rules! loadu_512 {
($src:expr) => {{
#[cfg(not(feature = "unchecked"))]
{
safe_unaligned_simd::x86_64::_mm512_loadu_si512($src)
}
#[cfg(feature = "unchecked")]
{
#[allow(unsafe_code)]
unsafe {
core::arch::x86_64::_mm512_loadu_si512(core::ptr::from_ref($src).cast())
}
}
}};
($slice:expr, $T:ty) => {{
#[cfg(not(feature = "unchecked"))]
{
safe_unaligned_simd::x86_64::_mm512_loadu_si512::<$T>(($slice).try_into().unwrap())
}
#[cfg(feature = "unchecked")]
{
let __s = $slice;
debug_assert!(core::mem::size_of_val(__s) >= 64);
#[allow(unsafe_code)]
unsafe {
core::arch::x86_64::_mm512_loadu_si512(__s.as_ptr() as *const _)
}
}
}};
}
#[cfg(target_arch = "x86_64")]
pub(crate) use loadu_512;
#[cfg(target_arch = "x86_64")]
macro_rules! storeu_512 {
($dst:expr, $val:expr) => {{
#[cfg(not(feature = "unchecked"))]
{
safe_unaligned_simd::x86_64::_mm512_storeu_si512($dst, $val)
}
#[cfg(feature = "unchecked")]
{
#[allow(unsafe_code)]
unsafe {
core::arch::x86_64::_mm512_storeu_si512(core::ptr::from_mut($dst).cast(), $val)
}
}
}};
($slice:expr, $T:ty, $val:expr) => {{
#[cfg(not(feature = "unchecked"))]
{
safe_unaligned_simd::x86_64::_mm512_storeu_si512::<$T>(
($slice).try_into().unwrap(),
$val,
)
}
#[cfg(feature = "unchecked")]
{
let __s = $slice;
debug_assert!(core::mem::size_of_val(__s) >= 64);
#[allow(unsafe_code)]
unsafe {
core::arch::x86_64::_mm512_storeu_si512(__s.as_mut_ptr() as *mut _, $val)
}
}
}};
}
#[cfg(target_arch = "x86_64")]
pub(crate) use storeu_512;
#[cfg(target_arch = "x86_64")]
macro_rules! loadu_128 {
($src:expr) => {{
#[cfg(not(feature = "unchecked"))]
{
safe_unaligned_simd::x86_64::_mm_loadu_si128($src)
}
#[cfg(feature = "unchecked")]
{
#[allow(unsafe_code)]
unsafe {
core::arch::x86_64::_mm_loadu_si128(core::ptr::from_ref($src).cast())
}
}
}};
($slice:expr, $T:ty) => {{
#[cfg(not(feature = "unchecked"))]
{
safe_unaligned_simd::x86_64::_mm_loadu_si128::<$T>(($slice).try_into().unwrap())
}
#[cfg(feature = "unchecked")]
{
let __s = $slice;
debug_assert!(core::mem::size_of_val(__s) >= 16);
#[allow(unsafe_code)]
unsafe {
core::arch::x86_64::_mm_loadu_si128(__s.as_ptr() as *const _)
}
}
}};
}
#[cfg(target_arch = "x86_64")]
pub(crate) use loadu_128;
#[cfg(target_arch = "x86_64")]
macro_rules! storeu_128 {
($dst:expr, $val:expr) => {{
#[cfg(not(feature = "unchecked"))]
{
safe_unaligned_simd::x86_64::_mm_storeu_si128($dst, $val)
}
#[cfg(feature = "unchecked")]
{
#[allow(unsafe_code)]
unsafe {
core::arch::x86_64::_mm_storeu_si128(core::ptr::from_mut($dst).cast(), $val)
}
}
}};
($slice:expr, $T:ty, $val:expr) => {{
#[cfg(not(feature = "unchecked"))]
{
safe_unaligned_simd::x86_64::_mm_storeu_si128::<$T>(($slice).try_into().unwrap(), $val)
}
#[cfg(feature = "unchecked")]
{
let __s = $slice;
debug_assert!(core::mem::size_of_val(__s) >= 16);
#[allow(unsafe_code)]
unsafe {
core::arch::x86_64::_mm_storeu_si128(__s.as_mut_ptr() as *mut _, $val)
}
}
}};
}
#[cfg(target_arch = "x86_64")]
pub(crate) use storeu_128;
#[cfg(target_arch = "x86_64")]
macro_rules! loadi32 {
($src:expr) => {{
let bytes: &[u8] = $src;
let val = i32::from_ne_bytes([bytes[0], bytes[1], bytes[2], bytes[3]]);
core::arch::x86_64::_mm_cvtsi32_si128(val)
}};
}
#[cfg(target_arch = "x86_64")]
pub(crate) use loadi32;
#[cfg(target_arch = "x86_64")]
macro_rules! storei32 {
($dst:expr, $val:expr) => {{
let val = core::arch::x86_64::_mm_cvtsi128_si32($val);
let bytes = val.to_ne_bytes();
let dst: &mut [u8] = $dst;
dst[0] = bytes[0];
dst[1] = bytes[1];
dst[2] = bytes[2];
dst[3] = bytes[3];
}};
}
#[cfg(target_arch = "x86_64")]
pub(crate) use storei32;
#[cfg(target_arch = "x86_64")]
macro_rules! loadi64 {
($src:expr) => {{
let bytes: &[u8] = $src;
let lo = i64::from_ne_bytes([
bytes[0], bytes[1], bytes[2], bytes[3], bytes[4], bytes[5], bytes[6], bytes[7],
]);
core::arch::x86_64::_mm_set_epi64x(0, lo)
}};
}
#[cfg(target_arch = "x86_64")]
pub(crate) use loadi64;
#[cfg(target_arch = "x86_64")]
macro_rules! storei64 {
($dst:expr, $val:expr) => {{
let val = core::arch::x86_64::_mm_cvtsi128_si64($val);
let bytes = val.to_ne_bytes();
let dst: &mut [u8] = $dst;
dst[..8].copy_from_slice(&bytes);
}};
}
#[cfg(target_arch = "x86_64")]
pub(crate) use storei64;
#[cfg(target_arch = "aarch64")]
macro_rules! neon_ld1q_u8 {
($src:expr) => {{
#[cfg(not(feature = "unchecked"))]
{
safe_unaligned_simd::aarch64::vld1q_u8($src)
}
#[cfg(feature = "unchecked")]
{
#[allow(unsafe_code)]
unsafe {
core::arch::aarch64::vld1q_u8(($src).as_ptr())
}
}
}};
}
#[cfg(target_arch = "aarch64")]
pub(crate) use neon_ld1q_u8;
#[cfg(target_arch = "aarch64")]
macro_rules! neon_ld1q_u16 {
($src:expr) => {{
#[cfg(not(feature = "unchecked"))]
{
safe_unaligned_simd::aarch64::vld1q_u16($src)
}
#[cfg(feature = "unchecked")]
{
#[allow(unsafe_code)]
unsafe {
core::arch::aarch64::vld1q_u16(($src).as_ptr())
}
}
}};
}
#[cfg(target_arch = "aarch64")]
pub(crate) use neon_ld1q_u16;
#[cfg(target_arch = "aarch64")]
macro_rules! neon_ld1q_s16 {
($src:expr) => {{
#[cfg(not(feature = "unchecked"))]
{
safe_unaligned_simd::aarch64::vld1q_s16($src)
}
#[cfg(feature = "unchecked")]
{
#[allow(unsafe_code)]
unsafe {
core::arch::aarch64::vld1q_s16(($src).as_ptr())
}
}
}};
}
#[cfg(target_arch = "aarch64")]
pub(crate) use neon_ld1q_s16;
#[cfg(target_arch = "aarch64")]
macro_rules! neon_st1q_u8 {
($dst:expr, $val:expr) => {{
#[cfg(not(feature = "unchecked"))]
{
safe_unaligned_simd::aarch64::vst1q_u8($dst, $val)
}
#[cfg(feature = "unchecked")]
{
#[allow(unsafe_code)]
unsafe {
core::arch::aarch64::vst1q_u8(($dst).as_mut_ptr(), $val)
}
}
}};
}
#[cfg(target_arch = "aarch64")]
pub(crate) use neon_st1q_u8;
#[cfg(target_arch = "aarch64")]
macro_rules! neon_st1q_u16 {
($dst:expr, $val:expr) => {{
#[cfg(not(feature = "unchecked"))]
{
safe_unaligned_simd::aarch64::vst1q_u16($dst, $val)
}
#[cfg(feature = "unchecked")]
{
#[allow(unsafe_code)]
unsafe {
core::arch::aarch64::vst1q_u16(($dst).as_mut_ptr(), $val)
}
}
}};
}
#[cfg(target_arch = "aarch64")]
pub(crate) use neon_st1q_u16;
#[cfg(target_arch = "wasm32")]
macro_rules! wasm_load_128 {
($src:expr) => {{
#[cfg(not(feature = "unchecked"))]
{
safe_unaligned_simd::wasm32::v128_load($src)
}
#[cfg(feature = "unchecked")]
{
#[allow(unsafe_code)]
unsafe {
core::arch::wasm32::v128_load(core::ptr::from_ref($src).cast())
}
}
}};
($slice:expr, $T:ty) => {{
#[cfg(not(feature = "unchecked"))]
{
safe_unaligned_simd::wasm32::v128_load::<$T>(($slice).try_into().unwrap())
}
#[cfg(feature = "unchecked")]
{
let __s = $slice;
debug_assert!(core::mem::size_of_val(__s) >= 16);
#[allow(unsafe_code)]
unsafe {
core::arch::wasm32::v128_load(__s.as_ptr() as *const _)
}
}
}};
}
#[cfg(target_arch = "wasm32")]
pub(crate) use wasm_load_128;
#[cfg(target_arch = "wasm32")]
macro_rules! wasm_store_128 {
($dst:expr, $val:expr) => {{
#[cfg(not(feature = "unchecked"))]
{
safe_unaligned_simd::wasm32::v128_store($dst, $val)
}
#[cfg(feature = "unchecked")]
{
#[allow(unsafe_code)]
unsafe {
core::arch::wasm32::v128_store(core::ptr::from_mut($dst).cast(), $val)
}
}
}};
($slice:expr, $T:ty, $val:expr) => {{
#[cfg(not(feature = "unchecked"))]
{
safe_unaligned_simd::wasm32::v128_store::<$T>(($slice).try_into().unwrap(), $val)
}
#[cfg(feature = "unchecked")]
{
let __s = $slice;
debug_assert!(core::mem::size_of_val(__s) >= 16);
#[allow(unsafe_code)]
unsafe {
core::arch::wasm32::v128_store(__s.as_mut_ptr() as *mut _, $val)
}
}
}};
}
#[cfg(target_arch = "wasm32")]
pub(crate) use wasm_store_128;
#[cfg(target_arch = "wasm32")]
macro_rules! wasm_loadi32 {
($src:expr) => {{
let bytes: &[u8] = $src;
let val = i32::from_ne_bytes([bytes[0], bytes[1], bytes[2], bytes[3]]);
core::arch::wasm32::i32x4(val, 0, 0, 0)
}};
}
#[cfg(target_arch = "wasm32")]
pub(crate) use wasm_loadi32;
#[cfg(target_arch = "wasm32")]
macro_rules! wasm_storei32 {
($dst:expr, $val:expr) => {{
let val = core::arch::wasm32::i32x4_extract_lane::<0>($val);
let bytes = val.to_ne_bytes();
let dst: &mut [u8] = $dst;
dst[0] = bytes[0];
dst[1] = bytes[1];
dst[2] = bytes[2];
dst[3] = bytes[3];
}};
}
#[cfg(target_arch = "wasm32")]
pub(crate) use wasm_storei32;
#[cfg(target_arch = "wasm32")]
#[allow(unused_macros)]
macro_rules! wasm_loadi64 {
($src:expr) => {{
let bytes: &[u8] = $src;
let lo = i64::from_ne_bytes([
bytes[0], bytes[1], bytes[2], bytes[3], bytes[4], bytes[5], bytes[6], bytes[7],
]);
core::arch::wasm32::i64x2(lo, 0)
}};
}
#[cfg(target_arch = "wasm32")]
#[allow(unused_imports)]
pub(crate) use wasm_loadi64;
#[cfg(target_arch = "wasm32")]
#[allow(unused_macros)]
macro_rules! wasm_storei64 {
($dst:expr, $val:expr) => {{
let val = core::arch::wasm32::i64x2_extract_lane::<0>($val);
let bytes = val.to_ne_bytes();
let dst: &mut [u8] = $dst;
dst[..8].copy_from_slice(&bytes);
}};
}
#[cfg(target_arch = "wasm32")]
#[allow(unused_imports)]
pub(crate) use wasm_storei64;
#[cfg(target_arch = "aarch64")]
macro_rules! neon_st1q_s16 {
($dst:expr, $val:expr) => {{
#[cfg(not(feature = "unchecked"))]
{
safe_unaligned_simd::aarch64::vst1q_s16($dst, $val)
}
#[cfg(feature = "unchecked")]
{
#[allow(unsafe_code)]
unsafe {
core::arch::aarch64::vst1q_s16(($dst).as_mut_ptr(), $val)
}
}
}};
}
#[cfg(target_arch = "aarch64")]
pub(crate) use neon_st1q_s16;