#[cfg(target_arch = "x86_64")]
use std::arch::x86_64::*;
#[cfg(target_arch = "aarch64")]
use std::arch::aarch64::*;
#[inline]
pub fn simd_find_newlines(bytes: &[u8]) -> u64 {
#[cfg(target_arch = "x86_64")]
unsafe {
simd_find_newlines_sse2(bytes)
}
#[cfg(target_arch = "aarch64")]
unsafe {
simd_find_newlines_neon(bytes)
}
#[cfg(not(any(target_arch = "x86_64", target_arch = "aarch64")))]
{
let mut mask = 0u64;
for (i, &b) in bytes.iter().enumerate().take(64) {
if b == b'\n' {
mask |= 1 << i;
}
}
mask
}
}
#[cfg(target_arch = "x86_64")]
#[target_feature(enable = "sse2")]
unsafe fn simd_find_newlines_sse2(bytes: &[u8]) -> u64 {
let len = bytes.len();
let mut mask = 0u64;
let newline = _mm_set1_epi8(b'\n' as i8);
let mut i = 0;
while i + 16 <= len {
let chunk = _mm_loadu_si128(bytes.as_ptr().add(i) as *const _);
let cmp = _mm_cmpeq_epi8(chunk, newline);
let m = _mm_movemask_epi8(cmp) as u64;
mask |= m << i;
i += 16;
}
if i < len {
for j in i..len {
if bytes[j] == b'\n' {
mask |= 1 << j;
}
}
}
mask
}
#[cfg(target_arch = "aarch64")]
#[target_feature(enable = "neon")]
unsafe fn simd_find_newlines_neon(bytes: &[u8]) -> u64 {
let len = bytes.len();
let mut mask = 0u64;
let newline = vdupq_n_u8(b'\n');
let mut i = 0;
while i + 16 <= len {
let chunk = vld1q_u8(bytes.as_ptr().add(i));
let cmp = vceqq_u8(chunk, newline);
let low = vgetq_lane_u64(vreinterpretq_u64_u8(cmp), 0);
let high = vgetq_lane_u64(vreinterpretq_u64_u8(cmp), 1);
let arr: [u8; 16] = std::mem::transmute(chunk);
for j in 0..16 {
if arr[j] == b'\n' {
mask |= 1 << (i + j);
}
}
i += 16;
}
if i < len {
for j in i..len {
if bytes[j] == b'\n' {
mask |= 1 << j;
}
}
}
mask
}
#[inline]
pub fn simd_statistics(values: &[f64]) -> (f64, f64, f64) {
#[cfg(target_arch = "x86_64")]
unsafe {
simd_statistics_avx2(values)
}
#[cfg(not(target_arch = "x86_64"))]
{
let mut min = f64::MAX;
let mut max = f64::MIN;
let mut sum = 0.0;
for &v in values {
if v < min { min = v; }
if v > max { max = v; }
sum += v;
}
if values.is_empty() {
(0.0, 0.0, 0.0)
} else {
(min, max, sum)
}
}
}
#[cfg(target_arch = "x86_64")]
#[target_feature(enable = "avx")]
unsafe fn simd_statistics_avx2(values: &[f64]) -> (f64, f64, f64) {
let len = values.len();
if len == 0 {
return (0.0, 0.0, 0.0);
}
let mut min_vec = _mm256_set1_pd(f64::MAX);
let mut max_vec = _mm256_set1_pd(f64::MIN);
let mut sum_vec = _mm256_setzero_pd();
let mut i = 0;
while i + 4 <= len {
let chunk = _mm256_loadu_pd(values.as_ptr().add(i));
min_vec = _mm256_min_pd(min_vec, chunk);
max_vec = _mm256_max_pd(max_vec, chunk);
sum_vec = _mm256_add_pd(sum_vec, chunk);
i += 4;
}
let mut min_arr = [0.0; 4];
let mut max_arr = [0.0; 4];
let mut sum_arr = [0.0; 4];
_mm256_storeu_pd(min_arr.as_mut_ptr(), min_vec);
_mm256_storeu_pd(max_arr.as_mut_ptr(), max_vec);
_mm256_storeu_pd(sum_arr.as_mut_ptr(), sum_vec);
let mut min = min_arr[0].min(min_arr[1]).min(min_arr[2]).min(min_arr[3]);
let mut max = max_arr[0].max(max_arr[1]).max(max_arr[2]).max(max_arr[3]);
let mut sum = sum_arr.iter().sum();
for j in i..len {
let v = values[j];
if v < min { min = v; }
if v > max { max = v; }
sum += v;
}
(min, max, sum)
}
#[inline]
pub fn simd_delta(curr: &[u64], prev: &[u64], out: &mut [u64]) {
let len = curr.len().min(prev.len()).min(out.len());
#[cfg(target_arch = "x86_64")]
unsafe {
simd_delta_avx2(curr, prev, out, len);
}
#[cfg(not(target_arch = "x86_64"))]
{
for i in 0..len {
out[i] = curr[i].saturating_sub(prev[i]);
}
}
}
#[cfg(target_arch = "x86_64")]
#[target_feature(enable = "avx2")]
unsafe fn simd_delta_avx2(curr: &[u64], prev: &[u64], out: &mut [u64], len: usize) {
let mut i = 0;
while i + 4 <= len {
let c = _mm256_loadu_si256(curr.as_ptr().add(i) as *const _);
let p = _mm256_loadu_si256(prev.as_ptr().add(i) as *const _);
let d = _mm256_sub_epi64(c, p); _mm256_storeu_si256(out.as_mut_ptr().add(i) as *mut _, d);
i += 4;
}
for j in i..len {
out[j] = curr[j].wrapping_sub(prev[j]);
}
}