pub use super::simd::*;
#[inline]
pub fn scirs2_simd_available() -> bool {
cfg!(feature = "simd")
}
#[inline]
pub fn scirs2_simd_alignment() -> usize {
64
}
#[repr(align(64))]
pub struct AlignedVec<T> {
data: Vec<T>,
alignment: usize,
}
impl<T: Clone> AlignedVec<T> {
pub fn with_capacity(capacity: usize) -> Self {
Self {
data: Vec::with_capacity(capacity),
alignment: scirs2_simd_alignment(),
}
}
pub fn from_vec(vec: Vec<T>) -> Self {
Self {
data: vec,
alignment: scirs2_simd_alignment(),
}
}
#[inline]
pub fn as_slice(&self) -> &[T] {
&self.data
}
#[inline]
pub fn as_mut_slice(&mut self) -> &mut [T] {
&mut self.data
}
#[inline]
pub fn alignment(&self) -> usize {
self.alignment
}
#[inline]
pub fn len(&self) -> usize {
self.data.len()
}
#[inline]
pub fn is_empty(&self) -> bool {
self.data.is_empty()
}
#[inline]
pub fn push(&mut self, value: T) {
self.data.push(value);
}
#[inline]
pub fn reserve(&mut self, additional: usize) {
self.data.reserve(additional);
}
#[inline]
pub fn clear(&mut self) {
self.data.clear();
}
}
impl<T: Clone> From<Vec<T>> for AlignedVec<T> {
fn from(vec: Vec<T>) -> Self {
Self::from_vec(vec)
}
}
impl<T> AsRef<[T]> for AlignedVec<T> {
fn as_ref(&self) -> &[T] {
&self.data
}
}
impl<T> AsMut<[T]> for AlignedVec<T> {
fn as_mut(&mut self) -> &mut [T] {
&mut self.data
}
}
pub mod aligned_ops {
use super::*;
#[inline]
pub fn aligned_add_f32(a: &[f32], b: &[f32], result: &mut [f32]) {
simd_add_f32(a, b, result);
}
#[inline]
pub fn aligned_mul_f32(a: &[f32], b: &[f32], result: &mut [f32]) {
simd_mul_f32(a, b, result);
}
#[inline]
pub fn aligned_dot_f32(a: &[f32], b: &[f32]) -> f32 {
simd_dot_f32(a, b)
}
#[inline]
pub fn aligned_sum_f32(a: &[f32]) -> f32 {
simd_sum_f32(a)
}
#[inline]
pub fn aligned_relu_f32(input: &[f32], output: &mut [f32]) {
simd_relu_f32(input, output);
}
#[inline]
pub fn aligned_sigmoid_f32(input: &[f32], output: &mut [f32]) {
simd_sigmoid_f32(input, output);
}
}
pub mod adaptive {
use super::*;
#[inline]
pub fn adaptive_add_f32(a: &[f32], b: &[f32], result: &mut [f32]) {
adaptive_simd_add_f32(a, b, result);
}
#[inline]
pub fn adaptive_mul_f32(a: &[f32], b: &[f32], result: &mut [f32]) {
adaptive_simd_mul_f32(a, b, result);
}
#[inline]
pub fn adaptive_dot_f32(a: &[f32], b: &[f32]) -> f32 {
adaptive_simd_dot_f32(a, b)
}
#[inline]
pub fn adaptive_matmul_f32(
a: &[f32],
b: &[f32],
result: &mut [f32],
m: usize,
n: usize,
k: usize,
) {
adaptive_simd_matmul_f32(a, b, result, m, n, k);
}
}
pub mod features {
#[inline]
pub fn has_avx2() -> bool {
super::has_avx2()
}
#[inline]
pub fn has_avx512() -> bool {
super::has_avx512()
}
#[inline]
pub fn has_neon() -> bool {
super::has_neon()
}
#[inline]
pub fn f32_vector_width() -> usize {
super::f32_vector_width()
}
#[inline]
pub fn f64_vector_width() -> usize {
super::f64_vector_width()
}
#[inline]
pub fn should_use_simd(size: usize) -> bool {
super::should_use_simd(size)
}
}
pub mod prelude {
pub use super::adaptive::*;
pub use super::aligned_ops::*;
pub use super::features::*;
pub use super::{scirs2_simd_alignment, scirs2_simd_available, AlignedVec};
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_scirs2_simd_available() {
let available = scirs2_simd_available();
#[cfg(feature = "simd")]
assert!(available);
#[cfg(not(feature = "simd"))]
assert!(!available);
}
#[test]
fn test_scirs2_simd_alignment() {
let alignment = scirs2_simd_alignment();
assert_eq!(alignment, 64);
assert!(alignment.is_power_of_two());
}
#[test]
fn test_aligned_vec_creation() {
let vec: AlignedVec<f32> = AlignedVec::with_capacity(10);
assert_eq!(vec.len(), 0);
assert_eq!(vec.alignment(), 64);
assert!(vec.is_empty());
}
#[test]
fn test_aligned_vec_from_vec() {
let data = vec![1.0f32, 2.0, 3.0, 4.0];
let aligned = AlignedVec::from_vec(data);
assert_eq!(aligned.len(), 4);
assert_eq!(aligned.as_slice(), &[1.0, 2.0, 3.0, 4.0]);
}
#[test]
fn test_aligned_vec_operations() {
let mut vec = AlignedVec::with_capacity(10);
vec.push(1.0f32);
vec.push(2.0);
vec.push(3.0);
assert_eq!(vec.len(), 3);
assert!(!vec.is_empty());
assert_eq!(vec.as_slice(), &[1.0, 2.0, 3.0]);
}
#[test]
fn test_aligned_add_f32() {
let a = vec![1.0f32, 2.0, 3.0, 4.0];
let b = vec![5.0f32, 6.0, 7.0, 8.0];
let mut result = vec![0.0f32; 4];
aligned_ops::aligned_add_f32(&a, &b, &mut result);
assert_eq!(result, vec![6.0, 8.0, 10.0, 12.0]);
}
#[test]
fn test_aligned_mul_f32() {
let a = vec![1.0f32, 2.0, 3.0, 4.0];
let b = vec![2.0f32, 3.0, 4.0, 5.0];
let mut result = vec![0.0f32; 4];
aligned_ops::aligned_mul_f32(&a, &b, &mut result);
assert_eq!(result, vec![2.0, 6.0, 12.0, 20.0]);
}
#[test]
fn test_aligned_dot_f32() {
let a = vec![1.0f32, 2.0, 3.0, 4.0];
let b = vec![2.0f32, 3.0, 4.0, 5.0];
let result = aligned_ops::aligned_dot_f32(&a, &b);
assert_eq!(result, 40.0);
}
#[test]
fn test_aligned_sum_f32() {
let a = vec![1.0f32, 2.0, 3.0, 4.0];
let result = aligned_ops::aligned_sum_f32(&a);
assert_eq!(result, 10.0);
}
#[test]
fn test_adaptive_add_f32() {
let a = vec![1.0f32, 2.0, 3.0, 4.0];
let b = vec![5.0f32, 6.0, 7.0, 8.0];
let mut result = vec![0.0f32; 4];
adaptive::adaptive_add_f32(&a, &b, &mut result);
assert_eq!(result, vec![6.0, 8.0, 10.0, 12.0]);
}
#[test]
fn test_feature_detection() {
let _ = features::has_avx2();
let _ = features::has_avx512();
let _ = features::has_neon();
let _ = features::f32_vector_width();
let _ = features::f64_vector_width();
assert!(features::should_use_simd(1000) || !cfg!(feature = "simd"));
}
}