Formatting only. cargo fmt --check was already failing on main (accel SIMD kernels, agent, format, migrate, bench); CI now enforces it. Co-Authored-By: Claude Fable 5.1 <[email protected]>
132 lines
3.8 KiB
Rust
132 lines
3.8 KiB
Rust
//! AVX-512 SIMD implementations for x86_64.
|
|
//! Gated behind the "avx512" feature flag.
|
|
//! All functions require runtime detection via is_x86_feature_detected!("avx512f").
|
|
|
|
#![cfg(all(target_arch = "x86_64", feature = "avx512"))]
|
|
|
|
#[cfg(target_arch = "x86_64")]
|
|
use std::arch::x86_64::*;
|
|
|
|
/// AVX-512 dot product for f32 slices.
|
|
///
|
|
/// # Safety
|
|
/// Caller must verify is_x86_feature_detected!("avx512f").
|
|
// SAFETY: Caller must have verified avx512f via is_x86_feature_detected!.
|
|
#[target_feature(enable = "avx512f")]
|
|
pub unsafe fn dot_product(a: &[f32], b: &[f32]) -> f32 {
|
|
unsafe {
|
|
assert_eq!(a.len(), b.len());
|
|
let len = a.len();
|
|
let mut i = 0;
|
|
let mut acc0 = _mm512_setzero_ps();
|
|
let mut acc1 = _mm512_setzero_ps();
|
|
|
|
// Process 32 elements per iteration (2x16 unrolled)
|
|
while i + 32 <= len {
|
|
let va0 = _mm512_loadu_ps(a.as_ptr().add(i));
|
|
let vb0 = _mm512_loadu_ps(b.as_ptr().add(i));
|
|
acc0 = _mm512_fmadd_ps(va0, vb0, acc0);
|
|
|
|
let va1 = _mm512_loadu_ps(a.as_ptr().add(i + 16));
|
|
let vb1 = _mm512_loadu_ps(b.as_ptr().add(i + 16));
|
|
acc1 = _mm512_fmadd_ps(va1, vb1, acc1);
|
|
|
|
i += 32;
|
|
}
|
|
|
|
if i + 16 <= len {
|
|
let va = _mm512_loadu_ps(a.as_ptr().add(i));
|
|
let vb = _mm512_loadu_ps(b.as_ptr().add(i));
|
|
acc0 = _mm512_fmadd_ps(va, vb, acc0);
|
|
i += 16;
|
|
}
|
|
|
|
let mut sum = _mm512_reduce_add_ps(_mm512_add_ps(acc0, acc1));
|
|
|
|
while i < len {
|
|
sum += a[i] * b[i];
|
|
i += 1;
|
|
}
|
|
|
|
sum
|
|
}
|
|
}
|
|
|
|
/// AVX-512 cosine similarity — fused single pass.
|
|
///
|
|
/// # Safety
|
|
/// Caller must verify is_x86_feature_detected!("avx512f").
|
|
// SAFETY: Caller must have verified avx512f via is_x86_feature_detected!.
|
|
#[target_feature(enable = "avx512f")]
|
|
pub unsafe fn cosine_similarity(a: &[f32], b: &[f32]) -> f32 {
|
|
unsafe {
|
|
assert_eq!(a.len(), b.len());
|
|
let len = a.len();
|
|
let mut i = 0;
|
|
|
|
let mut dot_acc = _mm512_setzero_ps();
|
|
let mut norm_a_acc = _mm512_setzero_ps();
|
|
let mut norm_b_acc = _mm512_setzero_ps();
|
|
|
|
while i + 16 <= len {
|
|
let va = _mm512_loadu_ps(a.as_ptr().add(i));
|
|
let vb = _mm512_loadu_ps(b.as_ptr().add(i));
|
|
dot_acc = _mm512_fmadd_ps(va, vb, dot_acc);
|
|
norm_a_acc = _mm512_fmadd_ps(va, va, norm_a_acc);
|
|
norm_b_acc = _mm512_fmadd_ps(vb, vb, norm_b_acc);
|
|
i += 16;
|
|
}
|
|
|
|
let mut dot = _mm512_reduce_add_ps(dot_acc);
|
|
let mut norm_a = _mm512_reduce_add_ps(norm_a_acc);
|
|
let mut norm_b = _mm512_reduce_add_ps(norm_b_acc);
|
|
|
|
while i < len {
|
|
dot += a[i] * b[i];
|
|
norm_a += a[i] * a[i];
|
|
norm_b += b[i] * b[i];
|
|
i += 1;
|
|
}
|
|
|
|
let denom = (norm_a * norm_b).sqrt();
|
|
if denom < f32::EPSILON {
|
|
0.0
|
|
} else {
|
|
dot / denom
|
|
}
|
|
}
|
|
}
|
|
|
|
/// AVX-512 L2 distance.
|
|
///
|
|
/// # Safety
|
|
/// Caller must verify is_x86_feature_detected!("avx512f").
|
|
// SAFETY: Caller must have verified avx512f via is_x86_feature_detected!.
|
|
#[target_feature(enable = "avx512f")]
|
|
pub unsafe fn l2_distance(a: &[f32], b: &[f32]) -> f32 {
|
|
unsafe {
|
|
assert_eq!(a.len(), b.len());
|
|
let len = a.len();
|
|
let mut i = 0;
|
|
let mut acc = _mm512_setzero_ps();
|
|
|
|
while i + 16 <= len {
|
|
let va = _mm512_loadu_ps(a.as_ptr().add(i));
|
|
let vb = _mm512_loadu_ps(b.as_ptr().add(i));
|
|
let diff = _mm512_sub_ps(va, vb);
|
|
acc = _mm512_fmadd_ps(diff, diff, acc);
|
|
i += 16;
|
|
}
|
|
|
|
let mut sum = _mm512_reduce_add_ps(acc);
|
|
|
|
while i < len {
|
|
let d = a[i] - b[i];
|
|
sum += d * d;
|
|
i += 1;
|
|
}
|
|
|
|
sum.sqrt()
|
|
}
|
|
}
|