utils/simd/
array.rs

1//! Array vector implementations.
2//!
3//! Setting `N` to 1 could replace the scalar implementation, but is significantly slower in
4//! unoptimised builds.
5
6// #[inline(always)] significantly improves performance
7#![allow(clippy::inline_always)]
8
9use std::array::from_fn;
10use std::ops::{Add, BitAnd, BitOr, BitXor, Not};
11
12#[derive(Clone, Copy)]
13#[repr(transparent)]
14pub struct U32Vector<const N: usize>([u32; N]);
15
16impl<const N: usize> From<[u32; N]> for U32Vector<N> {
17    #[inline]
18    fn from(value: [u32; N]) -> Self {
19        U32Vector(value)
20    }
21}
22
23impl<const N: usize> From<U32Vector<N>> for [u32; N] {
24    #[inline]
25    fn from(value: U32Vector<N>) -> Self {
26        value.0
27    }
28}
29
30impl<const N: usize> Add for U32Vector<N> {
31    type Output = Self;
32
33    #[inline(always)]
34    fn add(self, rhs: Self) -> Self::Output {
35        Self(from_fn(|i| self.0[i].wrapping_add(rhs.0[i])))
36    }
37}
38
39impl<const N: usize> BitAnd for U32Vector<N> {
40    type Output = Self;
41
42    #[inline(always)]
43    fn bitand(self, rhs: Self) -> Self::Output {
44        Self(from_fn(|i| self.0[i] & rhs.0[i]))
45    }
46}
47
48impl<const N: usize> BitOr for U32Vector<N> {
49    type Output = Self;
50
51    #[inline(always)]
52    fn bitor(self, rhs: Self) -> Self::Output {
53        Self(from_fn(|i| self.0[i] | rhs.0[i]))
54    }
55}
56
57impl<const N: usize> BitXor for U32Vector<N> {
58    type Output = Self;
59
60    #[inline(always)]
61    fn bitxor(self, rhs: Self) -> Self::Output {
62        Self(from_fn(|i| self.0[i] ^ rhs.0[i]))
63    }
64}
65
66impl<const N: usize> Not for U32Vector<N> {
67    type Output = Self;
68
69    #[inline(always)]
70    fn not(self) -> Self::Output {
71        Self(from_fn(|i| !self.0[i]))
72    }
73}
74
75impl<const N: usize> U32Vector<N> {
76    pub const LANES: usize = N;
77
78    #[inline(always)]
79    #[must_use]
80    pub fn andnot(self, rhs: Self) -> Self {
81        Self(from_fn(|i| self.0[i] & !rhs.0[i]))
82    }
83
84    #[inline(always)]
85    #[must_use]
86    pub fn splat(v: u32) -> Self {
87        Self([v; N])
88    }
89
90    #[inline(always)]
91    #[must_use]
92    pub fn rotate_left(self, n: u32) -> Self {
93        Self(from_fn(|i| self.0[i].rotate_left(n)))
94    }
95}
96
97/// 128-bit wide vector implementations using arrays.
98pub mod array128 {
99    /// The name of this backend.
100    pub const SIMD_BACKEND: &str = "array128";
101
102    /// Array vector with four [u32] lanes.
103    pub type U32Vector = super::U32Vector<4>;
104}
105
106/// 256-bit wide vector implementations using arrays.
107pub mod array256 {
108    /// The name of this backend.
109    pub const SIMD_BACKEND: &str = "array256";
110
111    /// Array vector with eight [u32] lanes.
112    pub type U32Vector = super::U32Vector<8>;
113}
114
115/// 4096-bit wide vector implementations using arrays.
116#[cfg(feature = "all-simd")]
117pub mod array4096 {
118    /// The name of this backend.
119    pub const SIMD_BACKEND: &str = "array4096";
120
121    /// Array vector with 128 [u32] lanes.
122    pub type U32Vector = super::U32Vector<128>;
123}