#![cfg_attr(not(feature = "std"), no_std)]
#![cfg_attr(target_arch = "spirv", feature(asm_experimental_arch))]
#[cfg(feature = "alloc")]
extern crate alloc;
pub const MAX_LANES: usize = 32;
pub const MAX_UNROLL: usize = 16;
pub mod backend;
pub mod arch;
pub mod dispatch;
#[cfg(not(hp_resolved_unroll))]
pub(crate) mod ilp;
pub mod dense;
pub mod matrix;
pub mod scalar;
pub mod varying;
#[cfg(feature = "alloc")]
pub mod cols;
#[cfg(feature = "alloc")]
pub mod soa;
#[cfg(feature = "glam")]
pub mod glam_ext;
pub use backend::{Backend, BackendAll, ScalarBackend};
pub use dispatch::{Kernel, SimdDispatch, dispatch, run_scalar};
#[cfg(target_arch = "spirv")]
pub use backend::subgroup::dispatch_subgroup;
pub use dense::{Diag, Mat, Side, Trans, Uplo, col_sums, fro_norm, gemv, row_sums};
#[cfg(feature = "alloc")]
pub use dense::{MatMut, gemm, potrf, syrk, trsm};
pub use matrix::{
Accumulator, Layout, MatrixA, MatrixB, MatrixBackend, MatrixDispatch, MatrixKernel, Role, Tile,
Tiles, dispatch_matrix, run_matrix_scalar,
};
pub use scalar::{FloatScalar, IntScalar, Scalar};
pub use varying::{ChunksExact, Varying, VaryingI32, VaryingU32, Mask, Gang};
pub use hydroplane_macros::kernel;
pub use half::{bf16, f16};
pub use num_traits;
#[cfg(feature = "alloc")]
pub use cols::Cols;
#[cfg(feature = "alloc")]
pub use soa::Soa;
#[cfg(feature = "glam")]
pub use glam_ext::{GangGlamExt, Mat3Wide, MatWide, Vec3Wide};
#[doc(hidden)]
pub mod towers {
pub use crate::dispatch::tier::*;
pub use crate::ScalarBackend;
#[cfg(any(target_arch = "x86_64", target_arch = "x86"))]
pub use crate::backend::{
avx1::Avx1, avx2::Avx2, avx512::Avx512, avx512bf16::Avx512Bf16, avx512fp16::Avx512Fp16,
sse4::Sse4,
};
#[cfg(target_arch = "aarch64")]
pub use crate::backend::neon::Neon;
#[cfg(target_arch = "aarch64")]
pub use crate::backend::sve::Sve;
#[cfg(all(target_arch = "wasm32", target_feature = "simd128"))]
pub use crate::backend::wasm::Simd128;
#[cfg(all(target_arch = "wasm32", target_feature = "simd128", target_feature = "relaxed-simd"))]
pub use crate::backend::wasm::RelaxedSimd;
}
#[doc(hidden)]
pub fn ilp_detected_for_test() -> u8 {
#[cfg(not(hp_resolved_unroll))]
{
ilp::cached()
}
#[cfg(hp_resolved_unroll)]
{
varying::STATIC_UNROLL as u8
}
}
#[cfg(test)]
mod tests {
use super::*;
fn any_within<T: Scalar, S: Backend<T>>(s: S, xs: &[T], r: T) -> bool {
let lanes = s.lanes();
let rv = s.splat(r);
let mut i = 0;
while i + lanes <= xs.len() {
let x = s.load(&xs[i..i + lanes]);
let ax = s.max(x, s.neg(x)); if s.any(s.le(ax, rv)) {
return true;
}
i += lanes;
}
while i < xs.len() {
if xs[i] <= r && xs[i].neg() <= r {
return true;
}
i += 1;
}
false
}
#[test]
fn scalar_backend_smoke() {
let xs = [3.0f32, -2.0, 5.0, 0.5];
assert!(any_within(ScalarBackend, &xs, 1.0));
assert!(!any_within(ScalarBackend, &xs, 0.4));
let xd = [3.0f64, -2.0, 5.0, 0.5];
assert!(any_within(ScalarBackend, &xd, 1.0));
assert!(!any_within(ScalarBackend, &xd, 0.4));
}
struct AnyWithin<'a, T: Scalar> {
xs: &'a [T],
r: T,
}
impl<T: Scalar> Kernel<T> for AnyWithin<'_, T> {
type Output = bool;
fn run<S: backend::BackendAll + Backend<T>>(self, simd: Gang<S>) -> bool {
any_within(simd.backend(), self.xs, self.r)
}
}
#[test]
fn dispatch_matches_scalar_oracle() {
let xs: Vec<f32> = (0..1000).map(|i| (i as f32 % 13.0) - 6.0).collect();
for &r in &[0.1f32, 0.5, 1.0, 3.0] {
let dispatched = dispatch(AnyWithin { xs: &xs, r });
let oracle = any_within(ScalarBackend, &xs, r);
assert_eq!(dispatched, oracle, "r={r}");
}
}
}