1#![cfg_attr(not(feature = "std"), no_std)]
9#![cfg_attr(target_arch = "spirv", feature(asm_experimental_arch))]
13
14#[cfg(feature = "alloc")]
15extern crate alloc;
16
17pub const MAX_LANES: usize = 32;
21
22pub const MAX_UNROLL: usize = 16;
26
27pub mod backend;
28pub mod arch;
29pub mod dispatch;
30#[cfg(not(hp_resolved_unroll))]
32pub(crate) mod ilp;
33pub mod dense;
34pub mod matrix;
35pub mod scalar;
36pub mod varying;
37
38#[cfg(feature = "alloc")]
39pub mod cols;
40#[cfg(feature = "alloc")]
41pub mod soa;
42
43#[cfg(feature = "glam")]
46pub mod glam_ext;
47
48pub use backend::{Backend, BackendAll, ScalarBackend};
49pub use dispatch::{Kernel, SimdDispatch, dispatch, run_scalar};
50
51#[cfg(target_arch = "spirv")]
54pub use backend::subgroup::dispatch_subgroup;
55pub use dense::{Diag, Mat, Side, Trans, Uplo, col_sums, fro_norm, gemv, row_sums};
56#[cfg(feature = "alloc")]
57pub use dense::{MatMut, gemm, potrf, syrk, trsm};
58pub use matrix::{
59 Accumulator, Layout, MatrixA, MatrixB, MatrixBackend, MatrixDispatch, MatrixKernel, Role, Tile,
60 Tiles, dispatch_matrix, run_matrix_scalar,
61};
62pub use scalar::{FloatScalar, IntScalar, Scalar};
63pub use varying::{ChunksExact, Varying, VaryingI32, VaryingU32, Mask, Gang};
64
65pub use hydroplane_macros::kernel;
70
71pub use half::{bf16, f16};
73
74pub use num_traits;
78
79#[cfg(feature = "alloc")]
80pub use cols::Cols;
81#[cfg(feature = "alloc")]
82pub use soa::Soa;
83
84#[cfg(feature = "glam")]
85pub use glam_ext::{GangGlamExt, Mat3Wide, MatWide, Vec3Wide};
86
87#[doc(hidden)]
90pub mod towers {
91 pub use crate::dispatch::tier::*;
92 pub use crate::ScalarBackend;
93 #[cfg(any(target_arch = "x86_64", target_arch = "x86"))]
94 pub use crate::backend::{
95 avx1::Avx1, avx2::Avx2, avx512::Avx512, avx512bf16::Avx512Bf16, avx512fp16::Avx512Fp16,
96 sse4::Sse4,
97 };
98 #[cfg(target_arch = "aarch64")]
99 pub use crate::backend::neon::Neon;
100 #[cfg(target_arch = "aarch64")]
101 pub use crate::backend::sve::Sve;
102 #[cfg(all(target_arch = "wasm32", target_feature = "simd128"))]
103 pub use crate::backend::wasm::Simd128;
104 #[cfg(all(target_arch = "wasm32", target_feature = "simd128", target_feature = "relaxed-simd"))]
105 pub use crate::backend::wasm::RelaxedSimd;
106}
107
108#[doc(hidden)]
112pub fn ilp_detected_for_test() -> u8 {
113 #[cfg(not(hp_resolved_unroll))]
114 {
115 ilp::cached()
116 }
117 #[cfg(hp_resolved_unroll)]
118 {
119 varying::STATIC_UNROLL as u8
120 }
121}
122
123#[cfg(test)]
124mod tests {
125 use super::*;
126
127 fn any_within<T: Scalar, S: Backend<T>>(s: S, xs: &[T], r: T) -> bool {
130 let lanes = s.lanes();
131 let rv = s.splat(r);
132 let mut i = 0;
133 while i + lanes <= xs.len() {
134 let x = s.load(&xs[i..i + lanes]);
135 let ax = s.max(x, s.neg(x)); if s.any(s.le(ax, rv)) {
137 return true;
138 }
139 i += lanes;
140 }
141 while i < xs.len() {
143 if xs[i] <= r && xs[i].neg() <= r {
144 return true;
145 }
146 i += 1;
147 }
148 false
149 }
150
151 #[test]
152 fn scalar_backend_smoke() {
153 let xs = [3.0f32, -2.0, 5.0, 0.5];
154 assert!(any_within(ScalarBackend, &xs, 1.0));
155 assert!(!any_within(ScalarBackend, &xs, 0.4));
156
157 let xd = [3.0f64, -2.0, 5.0, 0.5];
158 assert!(any_within(ScalarBackend, &xd, 1.0));
159 assert!(!any_within(ScalarBackend, &xd, 0.4));
160 }
161
162 struct AnyWithin<'a, T: Scalar> {
164 xs: &'a [T],
165 r: T,
166 }
167 impl<T: Scalar> Kernel<T> for AnyWithin<'_, T> {
168 type Output = bool;
169 fn run<S: backend::BackendAll + Backend<T>>(self, simd: Gang<S>) -> bool {
170 any_within(simd.backend(), self.xs, self.r)
171 }
172 }
173
174 #[test]
175 fn dispatch_matches_scalar_oracle() {
176 let xs: Vec<f32> = (0..1000).map(|i| (i as f32 % 13.0) - 6.0).collect();
178 for &r in &[0.1f32, 0.5, 1.0, 3.0] {
179 let dispatched = dispatch(AnyWithin { xs: &xs, r });
180 let oracle = any_within(ScalarBackend, &xs, r);
181 assert_eq!(dispatched, oracle, "r={r}");
182 }
183 }
184}