alloy/math/simd.rs
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223
//! The simd crate provides basic wrapper around the builtin simd types in the
//! Rust standard library.
pub(crate) mod common;
// Neon support
#[cfg(target_arch = "aarch64")]
mod float32x4_neon;
#[doc(inline)]
#[cfg(target_arch = "aarch64")]
pub use float32x4_neon::*;
// SSE support
// TODO: Implement SSE support
// No supported
#[cfg(not(target_arch = "aarch64"))]
mod float32x4_none;
#[doc(inline)]
#[cfg(not(target_arch = "aarch64"))]
pub use float32x4_none::*;
impl Float32x4 {
/// The alignment of the [Float32x4] type.
pub const ALIGN: usize = 16;
const ZERO: f32 = 0.0;
/// Create a new [Float32x4] from the elements within the slice, taking care
/// to handle both aligned and unaligned slices -- as well as padding slices
/// that contain less than 4 elements with zeros.
///
/// # Parameters
///
/// * `slice` - the slice of [f32] values to create the vector from
pub fn from_slice(slice: &[f32]) -> Self {
match slice.len() {
0 => Self::splat(Self::ZERO),
1 => Self::new(slice[0], Self::ZERO, Self::ZERO, Self::ZERO),
2 => Self::new(slice[0], slice[1], Self::ZERO, Self::ZERO),
3 => Self::new(slice[0], slice[1], slice[2], Self::ZERO),
_ => {
if slice.as_ptr().align_offset(Self::ALIGN) == 0 {
unsafe { Self::from_aligned_ptr(slice.as_ptr()) }
} else {
unsafe { Self::from_unaligned_ptr(slice.as_ptr()) }
}
}
}
}
/// Create a new [Float32x4] from the elements within the aligned slice.
///
/// # Parameters
///
/// * `slice` - the aligned slice of [f32] values to create the vector from
///
/// # Safety
///
/// The slice must be aligned to 16 bytes
pub unsafe fn from_aligned_slice(slice: &[f32]) -> Self {
match slice.len() {
0 => Self::splat(Self::ZERO),
1 => Self::new(slice[0], Self::ZERO, Self::ZERO, Self::ZERO),
2 => Self::new(slice[0], slice[1], Self::ZERO, Self::ZERO),
3 => Self::new(slice[0], slice[1], slice[2], Self::ZERO),
_ => Self::from_aligned_ptr(slice.as_ptr()),
}
}
/// Create a new [Float32x4] from the elements within the aligned slice.
///
/// # Parameters
///
/// * `slice` - the aligned slice of [f32] values to create the vector from
///
/// # Safety
///
/// The slice must be aligned to 16 bytes, and the length of the slice must be
/// a multiple of 4.
#[inline(always)]
pub unsafe fn from_aligned_slice_exact(slice: &[f32]) -> Self {
Self::from_aligned_ptr(slice.as_ptr())
}
/// Create a new [Float32x4] from the elements within the aligned slice.
///
/// # Parameters
///
/// * `slice` - the aligned slice of [f32] values to create the vector from
///
/// # Safety
///
/// The slice must contain a multiple of 4 elements.
pub unsafe fn from_unaligned_slice_exact(slice: &[f32]) -> Self {
Self::from_unaligned_ptr(slice.as_ptr())
}
/// Create a new [Float32x4] from the elements within the unaligned slice.
///
/// # Parameters
///
/// * `slice` - the unaligned slice of [f32] values to create the vector from
pub fn from_unaligned_slice(slice: &[f32]) -> Self {
match slice.len() {
0 => Self::splat(Self::ZERO),
1 => Self::new(slice[0], Self::ZERO, Self::ZERO, Self::ZERO),
2 => Self::new(slice[0], slice[1], Self::ZERO, Self::ZERO),
3 => Self::new(slice[0], slice[1], slice[2], Self::ZERO),
_ => unsafe { Self::from_unaligned_ptr(slice.as_ptr()) },
}
}
/// Returns an iterator that yields [Float32x4] values from the given slice.
///
/// If the slice is not divisible by 4, the remaining elements will be padded
/// with zeros.
///
/// # Parameters
///
/// * `slice` - the slice of [f32] values to create the vector from
pub fn iter_slice(slice: &[f32]) -> impl Iterator<Item = Self> + '_ {
slice.chunks(4).map(Self::from_slice)
}
/// Returns an iterator that yields [Float32x4] values from the given slice.
///
/// # Parameters
///
/// * `slice` - the slice of [f32] values to create the vector from
///
/// # Safety
///
/// The slice must contain a multiple of 4 elements.
pub unsafe fn iter_slice_exact(slice: &[f32]) -> impl Iterator<Item = Self> + '_ {
Float32x4ExactIter { slice }
}
}
struct Float32x4ExactIter<'a> {
slice: &'a [f32],
}
impl<'a> Iterator for Float32x4ExactIter<'a> {
type Item = Float32x4;
fn next(&mut self) -> Option<Self::Item> {
if self.slice.is_empty() {
return None;
}
let vec = unsafe { Float32x4::from_aligned_slice_exact(self.slice) };
self.slice = &self.slice[4..];
Some(vec)
}
}
impl FromIterator<f32> for Float32x4 {
/// Create a new [Float32x4] from the first 4 elements within the iterator.
///
/// # Parameters
///
/// * `iter` - the iterator of [f32] values to create the vector from
fn from_iter<I: IntoIterator<Item = f32>>(iter: I) -> Self {
let mut arr = common::F32x4Array::new([Self::ZERO; 4]);
for (i, val) in iter.into_iter().take(4).enumerate() {
arr[i] = val;
}
unsafe { Self::from_aligned_ptr(arr.as_ptr()) }
}
}
impl Default for Float32x4 {
/// Create a new [Float32x4] with all components set to zero.
#[inline(always)]
fn default() -> Self {
Self::splat(Self::ZERO)
}
}
impl From<[f32; 4]> for Float32x4 {
/// Create a new [Float32x4] from the given array of [f32] values.
///
/// # Parameters
///
/// * `arr` - the array of [f32] values to create the vector from
#[inline(always)]
fn from(arr: [f32; 4]) -> Self {
Self::from_slice(&arr)
}
}
impl From<&[f32]> for Float32x4 {
/// Create a new [Float32x4] from the given slice of [f32] values.
///
/// # Parameters
///
/// * `slice` - the slice of [f32] values to create the vector from
#[inline(always)]
fn from(slice: &[f32]) -> Self {
Self::from_slice(slice)
}
}
impl From<Float32x4> for [f32; 4] {
/// Create a new array of [f32] values from the given [Float32x4].
///
/// # Parameters
///
/// * `vec` - the [Float32x4] to create the array from
fn from(vec: Float32x4) -> Self {
let mut arr = [0.0; 4];
// SAFETY: The array is always aligned, and contains 4 elements.
unsafe { vec.store_aligned(arr.as_mut_ptr()) };
arr
}
}