Skip to main content

thermite/vector/
mod.rs

1#![warn(missing_docs)]
2#![allow(clippy::missing_safety_doc)]
3#![deny(unconditional_recursion)] // just in case we miss one
4
5//! User-facing vector types and the trait hierarchy that defines them.
6//!
7//! This module is the top of Thermite's public API. It provides the
8//! [`Vector<R>`] newtype - the value you actually compute with - and the tower
9//! of traits ([`GenericVector`] and its descendants) that describe what a
10//! vector can do.
11//!
12//! # Generic over *behavior*, not over a backend
13//!
14//! The central idea of Thermite is that you write code against
15//! [`GenericVector`] (or a more specific trait like [`NumericVector`],
16//! [`FloatVector`], or [`IntegerVector`]) and let the caller pick the concrete
17//! type. That concrete type decides the ISA, the lane count, and the element
18//! type - your code does not name any of them:
19//!
20//! ```
21//! use thermite::prelude::*;
22//! use thermite::math::TranscendentalMath;
23//!
24//! // Works on any backend, any width, any float element type.
25//! fn gaussian<V: FloatVector + TranscendentalMath>(v: V) -> V {
26//!     (-v * v).exp()
27//! }
28//! ```
29//!
30//! Crucially, "generic" here is stronger than "generic over the hardware
31//! backend". A [`GenericVector`] is not required to be a dense array of scalars
32//! sitting in a hardware register at all. The trait describes an *algebra of
33//! lanes*, and anything that satisfies that algebra is a first-class vector.
34//!
35//! # Composable abstractions all the way up
36//!
37//! Because the trait bounds are the only contract, wrapper types that are not
38//! SIMD registers in any conventional sense can still implement the hierarchy
39//! and flow through the very same generic functions:
40//!
41//! - **Complex numbers** - a `Complex<V>` pairing two real vectors implements
42//!   the [`GenericVector`]/[`FloatVector`] traits, so a function written for
43//!   real `FloatVector`s operates transparently on complex data.
44//! - **Compensated arithmetic** - a double-double `Compensated<V>` that tracks
45//!   rounding error implements the same traits; existing generic code gains
46//!   extended precision just by being instantiated with it.
47//! - **Dual / hyperdual numbers** - automatic differentiation via the same
48//!   trait composition, so a generic numeric routine differentiates itself when
49//!   handed a dual type.
50//!
51//! And these compose: `Complex<Compensated<f32x8>>` is a perfectly valid vector
52//! type where every complex operation is carried out in compensated real
53//! arithmetic, all still SIMD-accelerated underneath. The function you wrote
54//! once against `FloatVector` does not change.
55//!
56//! # The trait hierarchy
57//!
58//! Each trait adds capability on top of the previous one; bound on the least
59//! specific trait that supplies the operations you need.
60//!
61//! ```text
62//! GenericVector          construction, lane access, memory I/O, gather/scatter,
63//!   |                    reinterpretation, map/fold/reduce, interleave
64//!   |- BitwiseVector     &, |, ^, !, andnot, ternlog
65//!   |   \- BitshiftVector   shifts, rotations, byte-shifts
66//!   \- PartialOrdVector  cmp_lt/le/gt/ge/eq/ne -> Mask
67//!       \- NumericVector    +, -, *, /, %, min/max/clamp, reductions, FMA
68//!            |- SignedVector     abs, signum, copysign, neg
69//!            |    \- FloatVector        sqrt, rcp/rsqrt, rounding, mix, consts
70//!            |         \- FloatVectorWithBits  ldexp/frexp, bit-level ops
71//!            \- IntegerVector    saturating/wrapping, popcount, dividers
72//!                 |              (also requires BitshiftVector)
73//!                 |- SignedIntegerVector    arithmetic shift, avg
74//!                 |                         (also requires SignedVector)
75//!                 \- UnsignedIntegerVector  is_power_of_two, parity, avg
76//! ```
77//!
78//! `FloatVector` and `SignedIntegerVector` both sit under [`SignedVector`];
79//! `SignedIntegerVector` additionally requires [`IntegerVector`], so it is the
80//! meeting point of the signed and integer branches. `IntegerVector` itself
81//! does **not** require [`SignedVector`] - unsigned integer vectors are
82//! integers without being signed.
83//!
84//! Alongside these, [`LinAlg3Vector`]/[`LinAlg4Vector`] add 3D/4D linear-algebra
85//! operations, and the `Swizzle`/[`Swizzle3`]/[`Swizzle4`] traits add lane
86//! permutation. Masked (`_c`/`_m`/`_z`) variants of most operations live in the
87//! [`ops`] submodule.
88//!
89//! Three layers cooperate to make all of this work: an `Element` (the scalar),
90//! a [`Register`](crate::register::Register) (the functional hardware layer),
91//! and [`Vector<R>`] (this module's ergonomic wrapper). Most users only ever
92//! touch the [`Vector`] layer and its traits.
93
94use generic_array::{GenericArray, typenum};
95
96use crate::{
97    BranchfreeDivider, Divider,
98    divider::Denominator,
99    element::FloatElementWithBits,
100    isa::InstructionSet,
101    mask::{CastMask, GenericMask, GenericSelectable},
102    math::{FloatConsts, policy::Policy},
103    register::{Element, FloatElement, Lanes, NativeCapability},
104};
105
106mod num;
107
108#[doc(hidden)]
109pub mod splat;
110
111#[allow(clippy::module_inception)]
112mod vector;
113
114/// Operator traits behind the vector arithmetic, plus the masked `_c` / `_m` / `_z`
115/// forms of each.
116///
117/// The vector traits in this module's parent list these as supertraits, so a
118/// `V: NumericVector` bound already carries `+`, `-`, `*` and their masked
119/// variants. Import from here only to name one directly, such as writing a
120/// generic bound on [`ops::Square`] or [`ops::BitAndNot`] alone.
121pub mod ops;
122pub mod streaming;
123pub mod unaligned;
124
125pub use self::num::NumVector;
126pub use self::splat::{NewConst, NewVector, SplatConst, SplatVector, VectorValue, const_new, const_splat};
127pub use self::vector::Vector;
128pub use crate::register::StreamGroup;
129
130/// Three vector types (`Self`, `A`, `B`) whose masks can all be freely cast to
131/// one another.
132///
133/// All three must share the same [`Lanes`](GenericVector::Lanes) count, and
134/// each one's [`Mask`](GenericVector::Mask) must implement [`CastMask`] into
135/// the other two. This is a convenience bound for generic code that selects or
136/// blends across vectors of different element types but identical width - e.g.
137/// using a mask produced from a float comparison to select lanes of an integer
138/// vector.
139///
140/// It is blanket-implemented for every triple of types satisfying the cast
141/// requirements, so it never needs to be implemented manually.
142pub trait MaskInteroperable<A, B>: GenericVector<Mask: CastMask<A::Mask> + CastMask<B::Mask>>
143where
144    A: GenericVector<Lanes = Self::Lanes, Mask: CastMask<Self::Mask> + CastMask<B::Mask>>,
145    B: GenericVector<Lanes = Self::Lanes, Mask: CastMask<Self::Mask> + CastMask<A::Mask>>,
146{
147}
148
149impl<T, A, B> MaskInteroperable<A, B> for T
150where
151    T: GenericVector<Mask: CastMask<A::Mask> + CastMask<B::Mask>>,
152    A: GenericVector<Lanes = T::Lanes, Mask: CastMask<T::Mask> + CastMask<B::Mask>>,
153    B: GenericVector<Lanes = T::Lanes, Mask: CastMask<T::Mask> + CastMask<A::Mask>>,
154{
155}
156
157/// [`MaskInteroperable`] plus bidirectional numeric ([`CastVector`]) conversion
158/// among `Self`, `A`, and `B`.
159///
160/// In addition to interoperable masks, this guarantees `Self`, `A`, and `B` can
161/// all be numerically cast into one another in either direction (`A`/`B` into
162/// `Self` *and* `Self` into `A`/`B`), so generic code can freely move operands
163/// of differing element types into whichever common type it needs before
164/// combining them. It does **not** require bit-level reinterpretation; for that
165/// see [`FullyInteroperable`].
166///
167/// Blanket-implemented for every triple satisfying the bounds.
168pub trait PartiallyInteroperable<A, B>:
169    GenericVector<Mask: CastMask<A::Mask> + CastMask<B::Mask>>
170    // casts
171    + CastVector<Self>
172    + CastVector<A>
173    + CastVector<B>
174where
175    A: CastVector<Self> + GenericVector<Lanes = Self::Lanes, Mask: CastMask<Self::Mask> + CastMask<B::Mask>>,
176    B: CastVector<Self> + GenericVector<Lanes = Self::Lanes, Mask: CastMask<Self::Mask> + CastMask<A::Mask>>,
177{
178}
179
180impl<V, A, B> PartiallyInteroperable<A, B> for V
181where
182    V: GenericVector<Mask: CastMask<A::Mask> + CastMask<B::Mask>>
183        // casts
184        + CastVector<V>
185        + CastVector<A>
186        + CastVector<B>,
187    A: CastVector<V> + GenericVector<Lanes = V::Lanes, Mask: CastMask<V::Mask> + CastMask<B::Mask>>,
188    B: CastVector<V> + GenericVector<Lanes = V::Lanes, Mask: CastMask<V::Mask> + CastMask<A::Mask>>,
189{
190}
191
192/// [`PartiallyInteroperable`] plus zero-cost bit-level reinterpretation
193/// ([`BitCastVector`]) among `Self`, `A`, and `B`.
194///
195/// The strongest of the three interoperability bounds: masks are mutually
196/// castable, the three element types convert numerically, *and* their bit
197/// patterns can be reinterpreted into one another. This is what a float vector
198/// needs against its own bits/signed-bits integer vectors (see
199/// [`FloatVectorWithBits`]) so that bit-twiddling algorithms can hop between the
200/// float view and the integer view with no instructions emitted.
201///
202/// Blanket-implemented for every triple satisfying the bounds.
203pub trait FullyInteroperable<A, B>:
204    GenericVector<Mask: CastMask<A::Mask> + CastMask<B::Mask>>
205    // bits
206    + BitCastVector<Self>
207    + BitCastVector<A>
208    + BitCastVector<B>
209    // casts
210    + CastVector<Self>
211    + CastVector<A>
212    + CastVector<B>
213where
214    A: BitCastVector<Self> + CastVector<Self> + GenericVector<Lanes = Self::Lanes, Mask: CastMask<Self::Mask> + CastMask<B::Mask>>,
215    B: BitCastVector<Self> + CastVector<Self> + GenericVector<Lanes = Self::Lanes, Mask: CastMask<Self::Mask> + CastMask<A::Mask>>,
216{
217}
218
219impl<V, A, B> FullyInteroperable<A, B> for V
220where
221    V: GenericVector<Mask: CastMask<A::Mask> + CastMask<B::Mask>>
222        // bits
223        + BitCastVector<V>
224        + BitCastVector<A>
225        + BitCastVector<B>
226        // casts
227        + CastVector<V>
228        + CastVector<A>
229        + CastVector<B>,
230    A: BitCastVector<V> + CastVector<V> + GenericVector<Lanes = V::Lanes, Mask: CastMask<V::Mask> + CastMask<B::Mask>>,
231    B: BitCastVector<V> + CastVector<V> + GenericVector<Lanes = V::Lanes, Mask: CastMask<V::Mask> + CastMask<A::Mask>>,
232{
233}
234
235/// Internal helpers for generic vectors.
236trait GenericVectorExt: GenericVector {
237    #[inline(always)]
238    fn len_to_indices<I: UnsignedIntegerVector>(len: usize) -> I {
239        let Ok(len) = <<I as GenericVector>::Element as TryFrom<usize>>::try_from(len) else {
240            #[cfg(feature = "std")]
241            panic!("Length {} exceeds maximum supported index for this vector type", len);
242
243            #[cfg(not(feature = "std"))]
244            panic!("Length exceeds maximum supported index for this vector type");
245        };
246
247        I::splat(len)
248    }
249}
250
251impl<V: GenericVector> GenericVectorExt for V {}
252
253/// An unsigned integer vector that can be used as the index operand for
254/// gather/scatter operations producing/consuming a vector of type `V`.
255///
256/// This is the inverse-facing companion to [`IndexableVector`]: where
257/// `IndexableVector<I>` is implemented on the gathered vector type, this is
258/// implemented on the index type. It is blanket-implemented for every index
259/// type `I` such that `V: IndexableVector<I>`, simply forwarding to `V`'s
260/// methods. The index lanes are element offsets (not byte offsets) and must
261/// match `V`'s lane count.
262///
263/// The methods here are the raw pointer primitives; prefer the safe,
264/// bounds-checked wrappers on [`GenericVector`] ([`gather`](GenericVector::gather),
265/// [`scatter`](GenericVector::scatter), etc.) instead of calling these directly.
266pub trait VectorIndices<V: GenericVector>: UnsignedIntegerVector<Lanes = V::Lanes> {
267    /// Gather one element of `V` per lane from `ptr[indices[lane]]`.
268    ///
269    /// # Safety
270    /// `ptr` must be valid for reads, and for every lane the offset
271    /// `indices[lane]` must land within the allocation `ptr` points into
272    /// (i.e. `ptr.add(indices[lane])` must be readable). Indices are not
273    /// bounds-checked.
274    unsafe fn gather_ptr(ptr: *const V::Element, indices: Self) -> V;
275
276    /// Like [`gather_ptr`](Self::gather_ptr), but only lanes where `mask` is
277    /// `true` are loaded; the rest are taken from `src`.
278    ///
279    /// # Safety
280    /// Same as [`gather_ptr`](Self::gather_ptr), but only the offsets for lanes
281    /// where `mask` is `true` need to be in bounds; masked-off lanes are not
282    /// accessed.
283    unsafe fn gather_ptr_m(src: V, mask: V::Mask, ptr: *const V::Element, indices: Self) -> V;
284
285    /// Like [`gather_ptr_m`](Self::gather_ptr_m), but masked-off lanes are
286    /// zeroed instead of taken from a source vector.
287    ///
288    /// # Safety
289    /// Same as [`gather_ptr_m`](Self::gather_ptr_m).
290    unsafe fn gather_ptr_z(mask: V::Mask, ptr: *const V::Element, indices: Self) -> V;
291
292    /// Scatter each lane of `value` to `ptr[indices[lane]]`.
293    ///
294    /// # Safety
295    /// `ptr` must be valid for writes, and for every lane the offset
296    /// `indices[lane]` must land within the allocation `ptr` points into.
297    /// Indices are not bounds-checked, and overlapping (duplicate) indices
298    /// produce an unspecified winning lane.
299    unsafe fn scatter_ptr(value: V, ptr: *mut V::Element, indices: Self);
300
301    /// Like [`scatter_ptr`](Self::scatter_ptr), but only lanes where `mask` is
302    /// `true` are written.
303    ///
304    /// # Safety
305    /// Same as [`scatter_ptr`](Self::scatter_ptr), but only the offsets for
306    /// lanes where `mask` is `true` need to be in bounds; masked-off lanes are
307    /// not written.
308    unsafe fn scatter_ptr_m(value: V, mask: V::Mask, ptr: *mut V::Element, indices: Self);
309}
310
311/// A vector type that supports gather/scatter using index vectors of type `I`.
312///
313/// Implemented on the gathered/scattered vector type (`Self`), parameterized by
314/// the unsigned integer index vector type `I` (which must share `Self`'s lane
315/// count). Backends with hardware gather/scatter (e.g. AVX2's `vpgatherdd`)
316/// provide an accelerated implementation; others fall back to scalar loops.
317///
318/// These are the raw pointer primitives; index lanes are element offsets, not
319/// byte offsets, and are not bounds-checked. Prefer the safe, bounds-checked
320/// [`GenericVector`] wrappers ([`gather`](GenericVector::gather),
321/// [`scatter`](GenericVector::scatter), etc.) in normal code.
322pub trait IndexableVector<I: UnsignedIntegerVector<Lanes = Self::Lanes>>: GenericVector {
323    /// Gather one element per lane from `ptr[indices[lane]]`.
324    ///
325    /// # Safety
326    /// `ptr` must be valid for reads, and every offset `indices[lane]` must
327    /// land within the allocation `ptr` points into. Indices are not
328    /// bounds-checked.
329    unsafe fn gather_ptr(ptr: *const Self::Element, indices: I) -> Self;
330
331    /// Like [`gather_ptr`](Self::gather_ptr), but only lanes where `mask` is
332    /// `true` are loaded; the rest are taken from `src`.
333    ///
334    /// # Safety
335    /// Same as [`gather_ptr`](Self::gather_ptr), but only the offsets for lanes
336    /// where `mask` is `true` need to be in bounds.
337    unsafe fn gather_ptr_m(src: Self, mask: Self::Mask, ptr: *const Self::Element, indices: I) -> Self;
338
339    /// Like [`gather_ptr_m`](Self::gather_ptr_m), but masked-off lanes are
340    /// zeroed instead of taken from a source vector.
341    ///
342    /// # Safety
343    /// Same as [`gather_ptr_m`](Self::gather_ptr_m).
344    unsafe fn gather_ptr_z(mask: Self::Mask, ptr: *const Self::Element, indices: I) -> Self;
345
346    /// Scatter each lane of `value` to `ptr[indices[lane]]`.
347    ///
348    /// # Safety
349    /// `ptr` must be valid for writes, and every offset `indices[lane]` must
350    /// land within the allocation `ptr` points into. Indices are not
351    /// bounds-checked; duplicate indices produce an unspecified winning lane.
352    unsafe fn scatter_ptr(value: Self, ptr: *mut Self::Element, indices: I);
353
354    /// Like [`scatter_ptr`](Self::scatter_ptr), but only lanes where `mask` is
355    /// `true` are written.
356    ///
357    /// # Safety
358    /// Same as [`scatter_ptr`](Self::scatter_ptr), but only the offsets for
359    /// lanes where `mask` is `true` need to be in bounds.
360    unsafe fn scatter_ptr_m(value: Self, mask: Self::Mask, ptr: *mut Self::Element, indices: I);
361}
362
363impl<I, V> VectorIndices<V> for I
364where
365    I: UnsignedIntegerVector<Lanes = V::Lanes>,
366    V: IndexableVector<I>,
367{
368    #[inline(always)]
369    unsafe fn gather_ptr(ptr: *const <V as GenericVector>::Element, indices: Self) -> V {
370        unsafe { V::gather_ptr(ptr, indices) }
371    }
372
373    #[inline(always)]
374    unsafe fn gather_ptr_m(
375        src: V,
376        mask: <V as GenericVector>::Mask,
377        ptr: *const <V as GenericVector>::Element,
378        indices: Self,
379    ) -> V {
380        unsafe { V::gather_ptr_m(src, mask, ptr, indices) }
381    }
382
383    #[inline(always)]
384    unsafe fn gather_ptr_z(
385        mask: <V as GenericVector>::Mask,
386        ptr: *const <V as GenericVector>::Element,
387        indices: Self,
388    ) -> V {
389        unsafe { V::gather_ptr_z(mask, ptr, indices) }
390    }
391
392    #[inline(always)]
393    unsafe fn scatter_ptr(value: V, ptr: *mut <V as GenericVector>::Element, indices: Self) {
394        unsafe { V::scatter_ptr(value, ptr, indices) }
395    }
396
397    #[inline(always)]
398    unsafe fn scatter_ptr_m(
399        value: V,
400        mask: <V as GenericVector>::Mask,
401        ptr: *mut <V as GenericVector>::Element,
402        indices: Self,
403    ) {
404        unsafe { V::scatter_ptr_m(value, mask, ptr, indices) }
405    }
406}
407
408/// Joining two `HALF`-width values into one double-width `Self`, and splitting
409/// back apart.
410///
411/// Implemented for both vectors and masks. `Self` has exactly twice the lane
412/// count of `HALF`. Most users should go through
413/// [`GenericVector::concat`] / [`GenericVector::split`] rather than naming this
414/// trait directly. Because the wide type can always be narrowed back to a half,
415/// `Concat` requires [`Extend`].
416pub trait Concat<HALF>: Extend<HALF> {
417    /// Build the double-width value from a `lo` and `hi` half, with `lo`'s lanes
418    /// occupying the lower half of the result and `hi`'s the upper half.
419    fn concat(lo: HALF, hi: HALF) -> Self;
420
421    /// Split into `(lo, hi)` halves, the inverse of [`concat`](Self::concat).
422    fn split(self) -> (HALF, HALF);
423}
424
425/// Zero-extend a narrower `FROM` value into a wider `Self`, and narrow back.
426///
427/// Implemented for both vectors and masks. Most users should go through
428/// [`GenericVector::extend`] / [`GenericVector::narrow`].
429pub trait Extend<FROM> {
430    /// Widen `v` into `Self`, placing `v`'s lanes in the lower half and filling
431    /// the upper half with zeros.
432    fn extend(v: FROM) -> Self;
433
434    /// Narrow back to `FROM` by keeping the lower lanes and discarding the
435    /// upper lanes.
436    fn narrow(self) -> FROM;
437}
438
439/// [`Concat`] specialized to vector types: `Self` is a [`GenericVector`] that is
440/// the concatenation of two `HALF` vectors of the same element type, and whose
441/// mask is likewise the concatenation of two `HALF` masks.
442///
443/// Blanket-implemented; this is the bound used by [`GenericVector::concat`] /
444/// [`GenericVector::split`].
445pub trait ConcatVector<HALF: GenericVector<Element = Self::Element>>:
446    Concat<HALF> + GenericVector<Mask: Concat<HALF::Mask>>
447{
448}
449
450/// Zero-extend vectors
451pub trait ExtendVector<FROM: GenericVector<Element = Self::Element>>:
452    Extend<FROM> + GenericVector<Mask: Extend<FROM::Mask>>
453{
454}
455
456impl<V: GenericVector, H: GenericVector<Element = V::Element>> ConcatVector<H> for V
457where
458    V: Concat<H>,
459    V::Mask: Concat<H::Mask>,
460{
461}
462impl<V: GenericVector, F: GenericVector<Element = V::Element>> ExtendVector<F> for V
463where
464    V: Extend<F>,
465    V::Mask: Extend<F::Mask>,
466{
467}
468
469/// A [`GenericVector`] whose lanes can be permuted by the
470/// [`Swizzle`](crate::swizzle::Swizzle) machinery for its lane count.
471///
472/// Blanket-implemented for every vector that satisfies the swizzle bound; it is
473/// the prerequisite for the human-readable swizzle traits ([`Swizzle3`],
474/// [`Swizzle4`]) and the [`swizzle!`](crate::swizzle) macro.
475pub trait SwizzleVector: GenericVector + crate::swizzle::Swizzle<Self::Lanes> {}
476impl<V> SwizzleVector for V where V: GenericVector + crate::swizzle::Swizzle<V::Lanes> {}
477
478/// Pairwise lane interleaving and its exact inverse, the building block for
479/// moving between array-of-structs and struct-of-arrays layouts.
480///
481/// [`interleave`](Self::interleave) zips two vectors into a low half and a high
482/// half, and [`deinterleave`](Self::deinterleave) undoes it. Both lower to one
483/// instruction per output on most backends (x86 `unpcklps` / `unpckhps`, NEON
484/// `zip1` / `zip2`).
485///
486/// This trait carries only that pair, so it can bound code that is not generic
487/// over a full vector. The radix-`N` generalizations for wider strides and
488/// group granularity live on [`GenericVector`] instead.
489pub trait Interleave: Sized {
490    /// Unpack and interleave elements from two vectors.
491    ///
492    /// The resulting two vectors contain the interleaved elements from the input vectors. e.g.,
493    /// for vectors `a = [a0, a1, a2, a3]` and `b = [b0, b1, b2, b3]`, the result will be
494    /// `([a0, b0, a1, b1], [a2, b2, a3, b3])`.
495    ///
496    /// # Note
497    ///
498    /// Unlike the native unpacklo/unpackhi instructions, at higher register widths
499    /// this will preserve the order of all elements, not just 128-bit chunks.
500    fn interleave(self, other: Self) -> (Self, Self);
501
502    /// Pack and deinterleave elements from two vectors. This is the inverse operation of `interleave`.
503    ///
504    /// The resulting vector contains the deinterleaved elements from the input vectors. e.g.,
505    /// for vectors `a = [a0, b0, a1, b1]` and `b = [a2, b2, a3, b3]`, the result will be
506    /// `[a0, a1, a2, a3]` and `[b0, b1, b2, b3]`.
507    fn deinterleave(self, other: Self) -> (Self, Self);
508}
509
510/// Core trait for generic vector types.
511///
512/// Provides the basis for further specialized vector traits. Every other vector
513/// trait in the hierarchy (`NumericVector`, `FloatVector`, `IntegerVector`, etc.)
514/// is built on top of this one.
515///
516/// A `GenericVector` is a fixed-length, immutable, copyable array of `Element`s
517/// laid out contiguously and aligned to its register's native alignment. The
518/// number of lanes is known at compile time via the [`LANES`](Self::LANES)
519/// constant and the [`Lanes`](Self::Lanes) associated type (a `typenum`).
520///
521/// All construction, lane access, memory I/O, gather/scatter, reinterpretation,
522/// and scalar-fallback (`map`/`fold`/`reduce`) operations live on this trait.
523/// Arithmetic, bitwise and float operations are added by the sub-traits.
524#[rustfmt::skip] #[thermite_macros::vector_trait]
525#[diagnostic::on_unimplemented(
526    message = "`{Self}` is not a Thermite vector type",
527    label = "not a SIMD vector",
528    note = "`GenericVector` is the root of Thermite's vector trait tower. It is implemented by `Vector<R>` (including the 1-lane scalar `Vector<f32>` / `Vector<f64>`) and by composite vector types such as `Dual`, `Complex`, and `Compensated`.",
529    note = "A bare scalar such as `f32` or `f64` is NOT a vector. Wrap it with `Vector::<f32>::splat(x)` (or `Vector(x)`) to get a 1-lane vector, or use the `ScalarMath` methods (`x.scalar_sin()`, ...) for one-off scalar math."
530)]
531pub trait GenericVector: 'static + Sized + Default + Copy + core::fmt::Debug
532    + const_default::ConstDefault
533    + SplatVector<Self::Element> + NewVector<Self::Element, Self::Lanes>
534    + GenericSelectable<SelectableMask = Self::Mask>
535    + crate::simd::HasIsa
536    + CastVector<Self>
537    + Interleave
538{
539    /// Scalar element type of the vector.
540    type Element: Element;
541
542    /// A vector with all elements zeroed.
543    const EMPTY: Self;
544
545    /// Number of lanes in the vector.
546    const LANES: usize;
547
548    /// Number of lanes in the vector, as a runtime value.
549    ///
550    /// Today this is always [`LANES`](Self::LANES), but prefer it over the constant in
551    /// loop bounds and address arithmetic: a future scalable-vector backend (SVE /
552    /// RISC-V V) can only report its lane count at runtime, and code written against
553    /// `lanes()` will carry over unchanged.
554    #[inline(always)]
555    fn lanes() -> usize {
556        Self::LANES
557    }
558
559    /// Number of lanes in the vector, as a typenum.
560    type Lanes: Lanes;
561
562    /// Unsigned Integer Type suitable for use with this vector.
563    type Unsigned: UnsignedIntegerVector<
564            Signed = Self::Signed,
565            Unsigned = Self::Unsigned,
566            Lanes = Self::Lanes,
567            Element = <Self::Element as Element>::Unsigned,
568            Mask: CastMask<Self::Mask> + CastMask<<Self::Signed as GenericVector>::Mask>,
569        > + CastVector<Self::Signed>
570        + BitCastVector<Self::Signed>;
571
572    /// SignedBits Integer Type suitable for use with this vector.
573    type Signed: SignedIntegerVector<
574            Signed = Self::Signed,
575            Unsigned = Self::Unsigned,
576            Lanes = Self::Lanes,
577            Element = <Self::Element as Element>::Signed,
578            Mask: CastMask<Self::Mask> + CastMask<<Self::Unsigned as GenericVector>::Mask>,
579        > + CastVector<Self::Unsigned>
580        + BitCastVector<Self::Unsigned>;
581
582    /// Mask type for this vector. Masks are semantically boolean vectors indicating
583    /// true or false for each lane. They may or may not be represented as actual bits.
584    type Mask: GenericMask
585        + CastMask<<Self::Unsigned as GenericVector>::Mask>
586        + CastMask<<Self::Signed as GenericVector>::Mask>;
587
588    /// Create a new vector from an array of elements.
589    ///
590    /// The array length `N` must equal [`LANES`](Self::LANES); this is enforced
591    /// at compile time by the `Const<N> == Lanes` bound.
592    fn new<const N: usize>(value: [Self::Element; N]) -> Self
593        where generic_array::typenum::Const<N>: generic_array::IntoArrayLength<ArrayLength = Self::Lanes>;
594
595    /// Consume the vector and return its elements as a `GenericArray`.
596    ///
597    /// This is the inverse of [`new`](Self::new); it copies lane-by-lane and
598    /// has no runtime cost beyond a register-to-memory store on backends where
599    /// the storage and array layouts are bit-identical (the common case).
600    fn into_array(self) -> GenericArray<Self::Element, Self::Lanes>;
601
602    /// Create a new vector from a single element by splatting it across all lanes.
603    #[masked] fn splat(value: Self::Element) -> Self;
604
605    /// Create a new vector with the first lane set to the given value, and all other lanes set to zero.
606    fn single(value: Self::Element) -> Self;
607
608    /// Combine two vectors of the same type into one wider vector,
609    /// with `self` as the lower half and `hi` as the upper half.
610    fn concat<INTO>(self, hi: Self) -> INTO
611    where
612        INTO: ConcatVector<Self, Element = Self::Element>,
613    {
614        <INTO as Concat<Self>>::concat(self, hi)
615    }
616
617    /// Split this vector into two narrower vectors of the same type, with the lower
618    /// lanes in the first vector and the upper lanes in the second vector.
619    fn split<INTO: GenericVector>(self) -> (INTO, INTO)
620    where
621        Self: ConcatVector<INTO, Element = INTO::Element>,
622    {
623        <Self as Concat<INTO>>::split(self)
624    }
625
626    /// Zero-extend a narrower vector into this wider vector type, placing the
627    /// original values in the lower lanes and filling the upper lanes with zeros.
628    fn extend<INTO>(self) -> INTO
629    where
630        INTO: ExtendVector<Self, Element = Self::Element>,
631    {
632        <INTO as Extend<Self>>::extend(self)
633    }
634
635    /// Narrow this wider vector into a narrower vector by taking the lower lanes.
636    ///
637    /// The upper lanes are discarded.
638    fn narrow<INTO: GenericVector>(self) -> INTO
639    where
640        Self: ExtendVector<INTO, Element = INTO::Element>,
641    {
642        <Self as Extend<INTO>>::narrow(self)
643    }
644
645    /// Align a slice of elements to the vector's lane count, returning the aligned portion and any unaligned head or tail.
646    ///
647    /// If the vector's size in bytes does not match the size of its elements times the lane count, this will
648    /// return the entire slice as unaligned and empty aligned/remaining parts. This is rare, but may occur
649    /// if using a generic vector type that doesn't correspond to an actual hardware vector (for example, a 3-lane vector).
650    #[inline(always)]
651    fn align_slice(slice: &[Self::Element]) -> (&[Self::Element], &[Self], &[Self::Element]) {
652        if const { size_of::<Self>() != (size_of::<Self::Element>() * Self::LANES) } {
653            return (slice, &[], &[]);
654        };
655
656        unsafe { slice.align_to() }
657    }
658
659    /// Align a mutable slice of elements to the vector's lane count, returning the aligned portion and any unaligned head or tail.
660    ///
661    /// If the vector's size in bytes does not match the size of its elements times the lane count, this will
662    /// return the entire slice as unaligned and empty aligned/remaining parts. This is rare, but may occur
663    /// if using a generic vector type that doesn't correspond to an actual hardware vector (for example, a 3-lane vector).
664    #[inline(always)]
665    fn align_slice_mut(slice: &mut [Self::Element]) -> (&mut [Self::Element], &mut [Self], &mut [Self::Element]) {
666        if const { size_of::<Self>() != (size_of::<Self::Element>() * Self::LANES) } {
667            return (slice, &mut [], &mut []);
668        };
669
670        unsafe { slice.align_to_mut() }
671    }
672
673    /// Create a new vector from a slice of elements. The slice must have at least as many elements as the vector's lanes.
674    ///
675    /// This will emit an unaligned load.
676    ///
677    /// If you're looking for masked variants of this, those typically only exist for aligned inputs,
678    /// so you'll need an aligned pointer and use [`load_m`](Self::load_m) or [`load_z`](Self::load_z).
679    fn from_slice(slice: &[Self::Element]) -> Self {
680        assert!(slice.len() >= Self::lanes(), "Slice must have at least {} elements to create a vector", Self::lanes());
681
682        unsafe { Self::load_unaligned(slice.as_ptr()) }
683    }
684
685    /// Copy the elements of the vector into a slice. The slice must have at least as many elements as the vector's lanes.
686    ///
687    /// This will emit an unaligned store.
688    fn copy_to_slice(self, slice: &mut [Self::Element]) {
689        assert!(slice.len() >= Self::lanes(), "Slice must have at least {} elements to copy from a vector", Self::lanes());
690
691        unsafe { self.store_unaligned(slice.as_mut_ptr()) }
692    }
693
694    /// Transform a slice of element values into an unaligned iterator of vectors,
695    /// returning any remaining elements as a suffix slice.
696    fn iter_unaligned<'a>(values: &'a [Self::Element]) -> (unaligned::Unaligned<'a, Self>, &'a [Self::Element]) {
697        let num_vectors = values.len() / Self::lanes();
698        let offset = num_vectors * Self::lanes();
699
700        let head = &values[..offset];
701        let tail = &values[offset..];
702
703        (unaligned::Unaligned(head), tail)
704    }
705
706    /// Transform a mutable slice of element values into an unaligned iterator of vectors,
707    /// returning any remaining elements as a suffix slice.
708    fn iter_mut_unaligned<'a>(values: &'a mut [Self::Element]) -> (unaligned::UnalignedMut<'a, Self>, &'a mut [Self::Element]) {
709        let num_vectors = values.len() / Self::lanes();
710        let offset = num_vectors * Self::lanes();
711
712        let (head, tail) = values.split_at_mut(offset);
713
714        (unaligned::UnalignedMut(head), tail)
715    }
716
717    /// Iterate over a slice of element values as Vectors using non-temporal (streaming) loads.
718    ///
719    /// # Panics
720    ///
721    /// If the slice is not aligned to the register type of the vector, or has remaining elements.
722    fn stream_aligned_slice<'a>(values: &'a [Self::Element]) -> impl DoubleEndedIterator<Item = streaming::StreamingVector<'a, Self>> {
723        let (&[], values, &[]) = Self::align_slice(values) else {
724            panic!("Slice is not aligned to the vector type, or has remaining elements");
725        };
726
727        values.iter().map(|v| streaming::StreamingVector(v))
728    }
729
730    /// Iterate over a mutable slice of element values as Vectors using non-temporal (streaming) loads and stores.
731    ///
732    /// # Panics
733    ///
734    /// If the slice is not aligned to the register type of the vector, or has remaining elements.
735    fn stream_aligned_slice_mut<'a>(values: &'a mut [Self::Element]) -> impl DoubleEndedIterator<Item = streaming::StreamingVectorMut<'a, Self>> {
736        let (&mut [], values, &mut []) = Self::align_slice_mut(values) else {
737            panic!("Slice is not aligned to the vector type, or has remaining elements");
738        };
739
740        values.iter_mut().map(|v| streaming::StreamingVectorMut(v))
741    }
742
743    /// Gather elements from memory at the specified indices and return a new vector with those elements.
744    ///
745    /// The provided indices are in number of elements, not bytes.
746    ///
747    /// # Panics
748    /// If any index is out of bounds for the slice length, or the slice length exceeds
749    /// the maximum supported index for this vector type.
750    fn gather<I: VectorIndices<Self>>(slice: &[Self::Element], indices: I) -> Self {
751        if indices.cmp_lt(Self::len_to_indices::<I>(slice.len())).all() {
752            unsafe { I::gather_ptr(slice.as_ptr(), indices) }
753        } else {
754            #[cfg(feature = "std")]
755            panic!("One or more indices are out of bounds for the slice length {}", slice.len());
756
757            #[cfg(not(feature = "std"))] // avoid fmt
758            panic!("One or more indices are out of bounds for the slice length");
759        }
760    }
761
762    /// Gather elements from memory at the specified indices, or return `or` if the index is out of bounds.
763    ///
764    /// The provided indices are in number of elements, not bytes.
765    ///
766    /// # Panics
767    /// If the slice length exceeds the maximum supported index for this vector type.
768    fn gather_or<I: VectorIndices<Self>>(slice: &[Self::Element], indices: I, or: Self) -> Self
769        where Self::Mask: CastMask<I::Mask>,
770    {
771        let in_bounds = indices.cmp_lt(Self::len_to_indices::<I>(slice.len()));
772
773        unsafe { I::gather_ptr_m(or, in_bounds.cast(), slice.as_ptr(), indices) }
774    }
775
776    /// Gather elements from memory at the specified indices, or set the lane to zero
777    /// if the index is out of bounds.
778    ///
779    /// The provided indices are in number of elements, not bytes.
780    ///
781    /// # Panics
782    /// If the slice length exceeds the maximum supported index for this vector type.
783    fn gather_or_zero<I: VectorIndices<Self>>(slice: &[Self::Element], indices: I) -> Self
784        where Self::Mask: CastMask<I::Mask>,
785    {
786        let in_bounds = indices.cmp_lt(Self::len_to_indices::<I>(slice.len()));
787
788        unsafe { I::gather_ptr_z(in_bounds.cast(), slice.as_ptr(), indices) }
789    }
790
791    /// Gather elements from memory at the specified indices, or return `or` if the `enable` mask is
792    /// `false` OR if any index is out of bounds.
793    ///
794    /// The provided indices are in number of elements, not bytes.
795    ///
796    /// # Panics
797    /// If the slice length exceeds the maximum supported index for this vector type.
798    fn gather_if<I: VectorIndices<Self>>(slice: &[Self::Element], enable: Self::Mask, indices: I, or: Self) -> Self
799    where
800        Self::Mask: CastMask<I::Mask>,
801        Self::Element: Default,
802    {
803        let in_bounds = indices.cmp_lt(Self::len_to_indices::<I>(slice.len()));
804
805        unsafe { I::gather_ptr_m(or, enable & in_bounds.cast(), slice.as_ptr(), indices) }
806    }
807
808    /// Scatter elements from the given vector into memory at the specified indices. If the index is outside of the
809    /// bounds of the provided slice, the write is suppressed without panicking.
810    fn scatter<I: VectorIndices<Self>>(self, slice: &mut [Self::Element], indices: I)
811        where Self::Mask: CastMask<I::Mask>,
812    {
813        let in_bounds = indices.cmp_lt(Self::len_to_indices::<I>(slice.len()));
814
815        unsafe { I::scatter_ptr_m(self, in_bounds.cast(), slice.as_mut_ptr(), indices) }
816    }
817
818    /// Scatter elements from the given vector into memory at the specified indices, but only for lanes where the `enable` mask is `true`.
819    /// If the index is outside of the bounds of the provided slice, the write is suppressed without panicking.
820    fn scatter_if<I: VectorIndices<Self>>(self, slice: &mut [Self::Element], enable: Self::Mask, indices: I)
821        where Self::Mask: CastMask<I::Mask>,
822    {
823        let in_bounds = indices.cmp_lt(Self::len_to_indices::<I>(slice.len()));
824
825        unsafe { I::scatter_ptr_m(self, enable & in_bounds.cast(), slice.as_mut_ptr(), indices) }
826    }
827
828    /// Load a vector from an **aligned** pointer to its elements.
829    ///
830    /// # SAFETY
831    /// The caller must ensure that the pointer is valid, aligned, and points to a memory region
832    /// that is at least `Self::Lanes` elements long.
833    #[masked] unsafe fn load(ptr: *const Self::Element) -> Self;
834
835    /// Load a vector from an **unaligned** pointer to its elements.
836    ///
837    /// # SAFETY
838    /// The caller must ensure that the pointer is valid and points to a memory region
839    /// that is at least `Self::Lanes` elements long.
840    ///
841    /// Unaligned access may be slower on some older architectures.
842    unsafe fn load_unaligned(ptr: *const Self::Element) -> Self;
843
844    /// Load a vector from a pointer to its elements using non-temporal (streaming) loads.
845    ///
846    /// The memory region should not be accessed frequently by the CPU,
847    /// as non-temporal loads are intended for data that will not be reused soon.
848    ///
849    /// # SAFETY
850    /// The caller must ensure that the pointer is valid, aligned, and points to a memory region
851    /// that is at least `Self::Lanes` elements long.
852    unsafe fn load_streaming(ptr: *const Self::Element) -> Self;
853
854    /// Store the vector to an **aligned** pointer to its elements.
855    ///
856    /// # SAFETY
857    /// The caller must ensure that the pointer is valid, aligned, and points to a memory region
858    /// that is at least `Self::Lanes` elements long.
859    unsafe fn store(self, ptr: *mut Self::Element);
860
861    /// Store the vector to an **aligned** pointer to its elements, but only for lanes where the corresponding mask lane is `true`.
862    /// For lanes where the mask is `false`, the store is suppressed without panicking.
863    ///
864    /// # SAFETY
865    /// The caller must ensure that the pointer is valid, aligned, and points to a memory region
866    /// that is at least `Self::Lanes` elements long (or at least as long as the number of `true` lanes in the mask).
867    unsafe fn store_masked(self, mask: Self::Mask, ptr: *mut Self::Element);
868
869    /// Store the vector to an **unaligned** pointer to its elements.
870    ///
871    /// # SAFETY
872    /// The caller must ensure that the pointer is valid and points to a memory region
873    /// that is at least `Self::Lanes` elements long. Unaligned access may be slower on some architectures.
874    ///
875    /// Unaligned access may be slower on some older architectures.
876    unsafe fn store_unaligned(self, ptr: *mut Self::Element);
877
878    /// Store the vector to a pointer to its elements using non-temporal (streaming) stores.
879    ///
880    /// The memory region should not be accessed frequently by the CPU,
881    /// as non-temporal stores are intended for data that will not be reused soon.
882    ///
883    /// # SAFETY
884    /// The caller must ensure that the pointer is valid, aligned, and points to a memory region
885    /// that is at least `Self::Lanes` elements long.
886    unsafe fn store_streaming(self, ptr: *mut Self::Element);
887
888    /// Interleave two vectors at **group granularity**: blocks of `GROUP` consecutive elements move
889    /// as a unit and are never split. `GROUP == 1` is [`interleave`](Interleave::interleave); `GROUP == 2`
890    /// is the complex interleave - `lo == [a.c0, b.c0, a.c1, b.c1, ...]` over the low half of the
891    /// groups, `hi` over the high half - which lowers to the doubled-element unpack (`unpacklo_pd` +
892    /// `permute2f128` on AVX2, `zip` on NEON) rather than a general permute. The primitive for
893    /// complex FFT transposes and any group-structured SIMD. `GROUP` must divide `LANES`.
894    ///
895    /// The register-level default forwards `GROUP == 1` to [`interleave`](Interleave::interleave) and uses
896    /// a lane-wise fallback otherwise; backends override the group sizes they do natively.
897    fn interleave_by<const GROUP: usize>(self, other: Self) -> (Self, Self);
898
899    /// The inverse of [`interleave_by`](Self::interleave_by) - group-granularity de-interleave.
900    fn deinterleave_by<const GROUP: usize>(self, other: Self) -> (Self, Self);
901
902    /// Radix-`N` interleave: the generic sibling of [`interleave`](Interleave::interleave)
903    /// (`N == 2`). Treats the `N` inputs as one contiguous `N * LANES` span and
904    /// gives `out` with `concat(out)[q * N + r] == inputs[r].extract(q)`.
905    ///
906    /// `N` is inferred from the array length, so no turbofish is needed:
907    /// `V::interleave_radix([a, b])` is the 2-way interleave. `N == 2` reuses the
908    /// native `interleave`, `N == 3` a native radix-3 register sequence; any other
909    /// `N` uses a single permute+blend gather. For the AoS<->SoA memory form over
910    /// arbitrary `N`, use [`load_deinterleaved`](Self::load_deinterleaved) /
911    /// [`store_interleaved`](Self::store_interleaved) instead.
912    fn interleave_radix<const N: usize>(inputs: [Self; N]) -> [Self; N];
913
914    /// The inverse of [`interleave_radix`](Self::interleave_radix) - radix-`N`
915    /// de-interleave: `out[r].extract(q) == concat(inputs)[q * N + r]`.
916    fn deinterleave_radix<const N: usize>(inputs: [Self; N]) -> [Self; N];
917
918    /// Group-granularity radix-`N` de-interleave: the two-axis unification of
919    /// [`deinterleave_radix`](Self::deinterleave_radix) (`GROUP == 1`) and
920    /// [`deinterleave_by`](Self::deinterleave_by) (`N == 2`). Each vector is viewed
921    /// as `LANES / GROUP` groups of `GROUP` consecutive elements; `out[r]` group `q`
922    /// is the `(q * N + r)`-th group of the concatenated input sequence, each group
923    /// moving as a unit.
924    ///
925    /// The square case `N == LANES / GROUP` is a register-array transpose of
926    /// `GROUP`-wide elements: `deinterleave_radix_by::<4, 2>` on 8-lane f32 is the
927    /// 4x4 interleaved-complex transpose (8 ops on AVX2), and
928    /// `deinterleave_radix_by::<4, 1>` on f64x4 is the 4x4 `f64` transpose - the
929    /// primitives for FFT codelets and small matrices. `GROUP` must divide `LANES`.
930    fn deinterleave_radix_by<const N: usize, const GROUP: usize>(inputs: [Self; N]) -> [Self; N];
931
932    /// The inverse of [`deinterleave_radix_by`](Self::deinterleave_radix_by) -
933    /// group-granularity radix-`N` interleave. For the square case it is the same
934    /// (self-inverse) register-array transpose.
935    fn interleave_radix_by<const N: usize, const GROUP: usize>(inputs: [Self; N]) -> [Self; N];
936
937    /// Load `N` interleaved (array-of-structures) streams and de-interleave them
938    /// into `N` vectors: reads `N * LANES` contiguous elements from `ptr` and
939    /// returns `out` with `out[j].extract(lane) == ptr[lane * N + j]`.
940    ///
941    /// The AoS -> SoA load. `N == 3` over `f32` is the classic case: a
942    /// `[[f32; 3]]` of `xyzxyzxyz...` becomes one vector each of `xxx`, `yyy`,
943    /// `zzz`. ARM lowers this to a single `LD2`/`LD3`/`LD4` (the de-interleave
944    /// happens in the load unit); elsewhere it is contiguous loads plus a
945    /// cross-register permute.
946    ///
947    /// No alignment is required beyond that of `Element`.
948    ///
949    /// # SAFETY
950    /// `ptr` must be valid for reads of `N * LANES` elements.
951    unsafe fn load_deinterleaved<const N: usize>(ptr: *const Self::Element) -> [Self; N];
952
953    /// Interleave `N` vectors and store them contiguously as an
954    /// array-of-structures: writes `N * LANES` elements such that
955    /// `ptr[lane * N + j] == values[j].extract(lane)`.
956    ///
957    /// The SoA -> AoS store, and the exact inverse of
958    /// [`load_deinterleaved`](Self::load_deinterleaved). Lowers to `ST2`/`ST3`/`ST4`
959    /// on ARM. No alignment is required beyond that of `Element`.
960    ///
961    /// # SAFETY
962    /// `ptr` must be valid for writes of `N * LANES` elements.
963    unsafe fn store_interleaved<const N: usize>(ptr: *mut Self::Element, values: [Self; N]);
964
965    /// Load `M` interleaved AoS records of `C` components each and de-interleave
966    /// them: reads `M * C * LANES` contiguous elements, and `out[j][c]` holds
967    /// component `c` of record `j`
968    /// (`out[j][c].extract(lane) == ptr[lane * M * C + j * C + c]`).
969    ///
970    /// This is the AoS -> SoA load for structured data: an array of 3D points is
971    /// `M = 1, C = 3`; an array of rays (origin + direction) is `M = 2, C = 3`.
972    /// See
973    /// [`Register::load_deinterleaved_arrays`](crate::register::Register::load_deinterleaved_arrays)
974    /// for how a backend serves it (NEON: an `LD3` per chunk).
975    ///
976    /// The default is a lane-wise gather - correct for ANY vector type, but
977    /// scalar. [`Vector`] overrides it with the register engine.
978    ///
979    /// # SAFETY
980    /// `ptr` must be valid for reads of `M * C * LANES` elements.
981    unsafe fn load_deinterleaved_arrays<const M: usize, const C: usize>(
982        ptr: *const Self::Element,
983    ) -> [[Self; C]; M] {
984        const { assert!(M >= 1 && C >= 1) };
985
986        let mut out = [[Self::EMPTY; C]; M];
987
988        let mut j = 0;
989        while j < M {
990            let mut c = 0;
991            while c < C {
992                let mut v = Self::EMPTY;
993
994                let mut lane = 0;
995                while lane < Self::LANES {
996                    v = v.insertv(lane, unsafe { ptr.add(lane * (M * C) + j * C + c).read_unaligned() });
997                    lane += 1;
998                }
999
1000                out[j][c] = v;
1001                c += 1;
1002            }
1003            j += 1;
1004        }
1005
1006        out
1007    }
1008
1009    /// Interleave `M` records of `C` components and store them contiguously - the
1010    /// exact inverse of
1011    /// [`load_deinterleaved_arrays`](Self::load_deinterleaved_arrays), with the
1012    /// same lane-wise default.
1013    ///
1014    /// # SAFETY
1015    /// `ptr` must be valid for writes of `M * C * LANES` elements.
1016    unsafe fn store_interleaved_arrays<const M: usize, const C: usize>(ptr: *mut Self::Element, values: [[Self; C]; M]) {
1017        const { assert!(M >= 1 && C >= 1) };
1018
1019        let mut j = 0;
1020        while j < M {
1021            let mut c = 0;
1022            while c < C {
1023                let v = values[j][c];
1024
1025                let mut lane = 0;
1026                while lane < Self::LANES {
1027                    unsafe { ptr.add(lane * (M * C) + j * C + c).write_unaligned(v.extractv(lane)) };
1028                    lane += 1;
1029                }
1030                c += 1;
1031            }
1032            j += 1;
1033        }
1034    }
1035
1036    /// Load `M` interleaved composite streams of `1 + TAIL` components each and
1037    /// de-interleave them into `M` [`StreamGroup`]s: reads
1038    /// `M * (TAIL + 1) * LANES` contiguous elements, and group `j`'s
1039    /// `head`/`tail[c - 1]` hold the de-interleaved components of composite
1040    /// stream `j`. See [`StreamGroup`] for why the component count is a
1041    /// separate const generic, and
1042    /// [`Register::load_deinterleaved_grouped`](crate::register::Register::load_deinterleaved_grouped)
1043    /// for the register-level strategy.
1044    ///
1045    /// The default is a lane-wise gather: correct for ANY vector type, but
1046    /// scalar. [`Vector`] overrides it with the register engine; a composite
1047    /// vector (dual numbers, compensated floats) instead implements its plain
1048    /// [`load_deinterleaved`](Self::load_deinterleaved) by calling *its inner
1049    /// vector's* grouped op with the composite's component count folded into
1050    /// `TAIL`. Only a composite nested inside another composite ever reaches
1051    /// this default - at that point layout-aware shuffling has run out of road,
1052    /// and correctness is all that is on offer.
1053    ///
1054    /// # SAFETY
1055    /// `ptr` must be valid for reads of `M * (TAIL + 1) * LANES` elements.
1056    unsafe fn load_deinterleaved_grouped<const M: usize, const TAIL: usize>(
1057        ptr: *const Self::Element,
1058    ) -> [StreamGroup<Self, TAIL>; M] {
1059        const { assert!(M >= 1) };
1060
1061        let c = TAIL + 1;
1062
1063        let mut out = [StreamGroup { head: Self::EMPTY, tail: [Self::EMPTY; TAIL] }; M];
1064
1065        let mut j = 0;
1066        while j < M {
1067            let mut comp = 0;
1068            while comp < c {
1069                let mut v = Self::EMPTY;
1070
1071                let mut lane = 0;
1072                while lane < Self::LANES {
1073                    v = v.insertv(lane, unsafe { ptr.add(lane * (M * c) + j * c + comp).read_unaligned() });
1074                    lane += 1;
1075                }
1076
1077                if comp == 0 {
1078                    out[j].head = v;
1079                } else {
1080                    out[j].tail[comp - 1] = v;
1081                }
1082                comp += 1;
1083            }
1084            j += 1;
1085        }
1086
1087        out
1088    }
1089
1090    /// Interleave `M` [`StreamGroup`]s and store them as a contiguous
1091    /// array-of-structures - the exact inverse of
1092    /// [`load_deinterleaved_grouped`](Self::load_deinterleaved_grouped), with
1093    /// the same lane-wise default and the same override expectations.
1094    ///
1095    /// # SAFETY
1096    /// `ptr` must be valid for writes of `M * (TAIL + 1) * LANES` elements.
1097    unsafe fn store_interleaved_grouped<const M: usize, const TAIL: usize>(
1098        ptr: *mut Self::Element,
1099        values: [StreamGroup<Self, TAIL>; M],
1100    ) {
1101        const { assert!(M >= 1) };
1102
1103        let c = TAIL + 1;
1104
1105        let mut j = 0;
1106        while j < M {
1107            let mut comp = 0;
1108            while comp < c {
1109                let v = if comp == 0 { values[j].head } else { values[j].tail[comp - 1] };
1110
1111                let mut lane = 0;
1112                while lane < Self::LANES {
1113                    unsafe { ptr.add(lane * (M * c) + j * c + comp).write_unaligned(v.extractv(lane)) };
1114                    lane += 1;
1115                }
1116                comp += 1;
1117            }
1118            j += 1;
1119        }
1120    }
1121
1122    /// Assemble a vector from a slice of elements and a vector of indices
1123    /// into that slice. If an index is outside the bounds of the given slice,
1124    /// the resulting lane will be the first element of the input slice.
1125    ///
1126    /// This is semantically equivalent to `gather`, but specialized for small lookup tables approximately
1127    /// the same size as the vector itself. If the lookup table is too large, it will fall back to `gather`.
1128    fn lookup(values: &[Self::Element], indices: Self::Unsigned) -> Self {
1129        let in_bounds = indices.cmp_lt(Self::len_to_indices::<Self::Unsigned>(values.len()));
1130
1131        unsafe { Self::lookup_unchecked(values, indices.zz(in_bounds)) }
1132    }
1133
1134    /// Assemble a vector from a slice of elements and a vector of indices
1135    /// into that slice. The indices are NOT checked to be within bounds.
1136    ///
1137    /// # Safety
1138    /// The caller must ensure that the indices are within bounds for the given values slice,
1139    /// otherwise this may panic or result in undefined behavior.
1140    unsafe fn lookup_unchecked(values: &[Self::Element], indices: Self::Unsigned) -> Self;
1141
1142    /// Broadcast the value of a single lane across all lanes of the vector.
1143    #[conditional] fn broadcast<const I: usize>(self) -> Self;
1144
1145    /// Broadcast the value of a single lane across all lanes of the vector.
1146    ///
1147    /// # Panics
1148    /// If `idx` is out of bounds for the vector's lanes.
1149    #[conditional] fn broadcastv(self, idx: usize) -> Self;
1150
1151    /// Extract a single element from the vector at the const-generic index `I`.
1152    ///
1153    /// Because `I` is known at compile time, the backend can lower this to a
1154    /// single instruction (e.g. `pextrd`) with no runtime branch.
1155    ///
1156    /// # Compile-time errors
1157    /// `I` must be less than [`LANES`](Self::LANES).
1158    fn extract<const I: usize>(self) -> Self::Element;
1159
1160    /// Extract lane 0 -- the scalar counterpart to [`single`](Self::single).
1161    ///
1162    /// `single` is the way *into* a vector from a bare scalar; this is the way back
1163    /// out. Together they are the whole scalar/SIMD boundary, and neither is free:
1164    /// lane 0 lives in a vector register, so reading it costs a cross-domain move
1165    /// (and a shuffle on backends without a lane-0 extract). Mixing scalar and SIMD
1166    /// code pays that on every crossing -- prefer staying in vector form.
1167    ///
1168    /// Equivalent to `self.extract::<0>()`, and lowered identically.
1169    #[inline(always)]
1170    fn first(self) -> Self::Element {
1171        self.extract::<0>()
1172    }
1173
1174    /// Extract a single element from the vector at the runtime index `idx`.
1175    ///
1176    /// Prefer [`extract`](Self::extract) when the index is known at compile
1177    /// time; this variant typically lowers to a small jump table or per-lane
1178    /// blend and is slower.
1179    ///
1180    /// # Panics
1181    /// If `idx` is out of bounds for the vector's lanes.
1182    fn extractv(self, idx: usize) -> Self::Element;
1183
1184    /// Replace a single element in the vector at the const-generic index `I`.
1185    ///
1186    /// Returns a new vector; the original is unmodified. The lane index is
1187    /// resolved at compile time.
1188    ///
1189    /// # Compile-time errors
1190    /// `I` must be less than [`LANES`](Self::LANES).
1191    fn insert<const I: usize>(self, value: Self::Element) -> Self;
1192
1193    /// Replace a single element in the vector at the runtime index `idx`.
1194    ///
1195    /// Prefer [`insert`](Self::insert) when the index is known at compile time.
1196    ///
1197    /// # Panics
1198    /// If `idx` is out of bounds for the vector's lanes.
1199    fn insertv(self, idx: usize, value: Self::Element) -> Self;
1200
1201    /// Reverse the order of the elements in the vector.
1202    ///
1203    /// For a vector `[a, b, c, d]` this returns `[d, c, b, a]`.
1204    #[conditional] fn reverse(self) -> Self;
1205
1206    /// Swap the byte order of each element in the vector, converting between
1207    /// little-endian and big-endian representations lane-by-lane.
1208    ///
1209    /// Only the bytes within each element are reordered; lane order is
1210    /// preserved. For a `u32` vector `[0x11223344]` this returns `[0x44332211]`.
1211    #[conditional] fn swap_bytes(self) -> Self;
1212
1213    /// (Zero If False) Zero elements if the corresponding mask lane is false; otherwise, leave unchanged.
1214    ///
1215    /// Similar to a `mask & self` operation.
1216    fn zz(self, mask: Self::Mask) -> Self;
1217
1218    /// (Zero If True) Zero elements if the corresponding mask lane is true; otherwise, leave unchanged.
1219    ///
1220    /// Similar to a `!mask & self` operation.
1221    fn nz(self, mask: Self::Mask) -> Self;
1222
1223    /// Construct a mask whose first `n` lanes are `true` and the remaining
1224    /// lanes `false`.
1225    ///
1226    /// `n` is clamped to [`LANES`](Self::LANES): `n >= LANES` yields an
1227    /// all-`true` mask and `n == 0` an all-`false` mask. This is the canonical
1228    /// tail-handling helper - given a remainder of `k < LANES` elements,
1229    /// `Self::prefix_mask(k)` selects exactly those lanes for a masked store,
1230    /// [`select`](crate::mask::GenericMask::select), or `_c`/`_m`/`_z`
1231    /// operation.
1232    ///
1233    /// Semantically `Self::indexed() < n` lifted into the mask domain, but
1234    /// available on any [`GenericVector`] (the predicate is built on
1235    /// [`Unsigned`](Self::Unsigned), so it does not require `Self: NumericVector`).
1236    #[inline(always)]
1237    fn prefix_mask(n: usize) -> Self::Mask {
1238        let n = if n > Self::lanes() { Self::lanes() } else { n };
1239        let limit = Self::len_to_indices::<Self::Unsigned>(n);
1240        Self::Unsigned::indexed().cmp_lt(limit).cast::<Self::Mask>()
1241    }
1242
1243    /// Construct a mask whose last `n` lanes are `true` and the remaining
1244    /// lanes `false`.
1245    ///
1246    /// `n` is clamped to [`LANES`](Self::LANES). This is the high-lane
1247    /// companion to [`prefix_mask`](Self::prefix_mask); for example
1248    /// `Self::suffix_mask(2)` on a 4-lane vector selects lanes 2 and 3.
1249    #[inline(always)]
1250    fn suffix_mask(n: usize) -> Self::Mask {
1251        let n = if n > Self::lanes() { Self::lanes() } else { n };
1252        let start = Self::len_to_indices::<Self::Unsigned>(Self::lanes() - n);
1253        Self::Unsigned::indexed().cmp_ge(start).cast::<Self::Mask>()
1254    }
1255
1256    /// Left-pack (a.k.a. `compress`): gather the lanes where `mask` is `true`
1257    /// into the low lanes, preserving their relative order. The unselected lanes
1258    /// are *kept* (not zeroed) and packed into the high lanes, also in order - a
1259    /// stable partition of the vector by `mask`.
1260    ///
1261    /// For `[a, b, c, d]` with `mask = [true, false, true, false]` this returns
1262    /// `[a, c, b, d]`. Combined with a masked store of the leading `mask`-count
1263    /// lanes, this is the building block for stream compaction - whitespace
1264    /// stripping, filtering, JSON minification, and similar. For the zero-filled
1265    /// tail variant, see [`compress_z`](Self::compress_z).
1266    ///
1267    /// Lowers to AVX-512 `vpcompress*` where available; otherwise a portable
1268    /// scalar partition (some backends accelerate it with a permute table).
1269    fn compress(self, mask: Self::Mask) -> Self;
1270
1271    /// Zero-filling left-pack: like [`compress`](Self::compress), but the lanes
1272    /// beyond the `mask` population count are zeroed instead of holding the
1273    /// unselected elements. Matches AVX-512 zero-masking `vpcompress*`.
1274    ///
1275    /// For `[a, b, c, d]` with `mask = [true, false, true, false]` this returns
1276    /// `[a, c, 0, 0]`.
1277    fn compress_z(self, mask: Self::Mask) -> Self;
1278
1279    /// Merge-masked left-pack: like [`compress`](Self::compress), but the lanes
1280    /// at and beyond the `mask` population count take their values from `src`
1281    /// (at their own positions). Matches AVX-512 merge-masked `vpcompress*`.
1282    ///
1283    /// This is the accumulator step of a buffered stream compactor: pack
1284    /// `self`'s selected lanes to the front while retaining `src`'s tail, then
1285    /// [`align`](Self::align) by the running count.
1286    ///
1287    /// For `self = [a, b, c, d]`, `src = [w, x, y, z]`,
1288    /// `mask = [true, false, true, false]` this returns `[a, c, y, z]`.
1289    fn compress_m(self, src: Self, mask: Self::Mask) -> Self;
1290
1291    /// Inverse left-pack (`expand`): scatter this vector's packed low lanes back
1292    /// out to the lanes where `mask` is set, preserving order; the unselected
1293    /// lanes read the tail. The **exact inverse permutation** of
1294    /// [`compress`](Self::compress):
1295    /// `v.compress(m).expand(m) == v` and `v.expand(m).compress(m) == v` for
1296    /// every `v` and `m`.
1297    ///
1298    /// For `[a, c, b, d]` with `mask = [true, false, true, false]` this returns
1299    /// `[a, b, c, d]` - the return trip of stream compaction (compact the
1300    /// active lanes, operate on the packed front, expand the results back to
1301    /// their home lanes).
1302    fn expand(self, mask: Self::Mask) -> Self;
1303
1304    /// Zero-filling inverse left-pack: like [`expand`](Self::expand), but the
1305    /// unselected lanes are zeroed. Matches AVX-512 zero-masking `vpexpand*`.
1306    ///
1307    /// For `[a, c, _, _]` with `mask = [true, false, true, false]` this returns
1308    /// `[a, 0, c, 0]`.
1309    fn expand_z(self, mask: Self::Mask) -> Self;
1310
1311    /// Merge-masked inverse left-pack: like [`expand`](Self::expand), but the
1312    /// unselected lanes take their values from `src`. Matches AVX-512
1313    /// merge-masked `vpexpand*`.
1314    ///
1315    /// For `self = [a, c, _, _]`, `src = [w, x, y, z]`,
1316    /// `mask = [true, false, true, false]` this returns `[a, x, c, z]` -
1317    /// equivalent to `mask.select(self.expand(mask), src)`.
1318    fn expand_m(self, src: Self, mask: Self::Mask) -> Self;
1319
1320    /// Two-register element align (the `palignr` family): the window of `LANES`
1321    /// lanes starting at lane `OFFSET` of the concatenation `[self, other]`
1322    /// (`self`'s lanes first, then `other`'s). `OFFSET == 0` returns `self`,
1323    /// `OFFSET == LANES` returns `other`; in between, lanes spill from the tail
1324    /// of `self` into the head of `other`.
1325    ///
1326    /// The cross-register sliding window used for scanning multi-byte
1327    /// delimiters / substrings across a load boundary. Works for any element
1328    /// type (it is pure lane movement); integer backends accelerate it with
1329    /// native byte aligns.
1330    fn align<const OFFSET: usize>(self, other: Self) -> Self;
1331
1332    /// Whether [`align`](Self::align) is a native cross-register instruction rather
1333    /// than the generic shuffle-and-blend fallback, forwarded from
1334    /// [`Register::HAS_NATIVE_ALIGN`](crate::register::Register::HAS_NATIVE_ALIGN).
1335    ///
1336    /// Both paths give the same results, so this only ever selects between
1337    /// lowerings: one instruction where the backend has a real align (`palignr`,
1338    /// `vext`, `i8x16.shuffle`), two permutes plus a blend where it has only
1339    /// variable permutes, and a scalar memory round-trip where it has neither.
1340    ///
1341    /// Gate on it when an algorithm is built from a *ladder* of aligns - the
1342    /// prefix-scan family is the one in-tree - since a ladder of emulated aligns can
1343    /// lose to walking the lanes outright. A composite vector forwards the flag from
1344    /// the vector it wraps, so `Dual`/`Compensated`/`Complex` report whatever their
1345    /// inner vector does.
1346    const HAS_NATIVE_ALIGN: bool;
1347
1348    /// Apply a function to each element in the vector, returning a new vector with the results.
1349    ///
1350    /// This is not explicitly SIMD-optimized, so may be slower than using native vector operations.
1351    fn map<F>(self, f: F) -> Self
1352    where
1353        F: Fn(Self::Element) -> Self::Element;
1354
1355    /// Fold the elements of the vector using the provided function and initial value.
1356    ///
1357    /// This is not explicitly SIMD-optimized, so may be slower than using native vector operations.
1358    fn fold<F>(self, init: Self::Element, f: F) -> Self::Element
1359    where
1360        F: Fn(Self::Element, Self::Element) -> Self::Element;
1361
1362    /// Reduce the elements of the vector using the provided function.
1363    ///
1364    /// This is not explicitly SIMD-optimized, so may be slower than using native vector operations.
1365    fn reduce<F>(self, f: F) -> Self::Element
1366    where
1367        F: Fn(Self::Element, Self::Element) -> Self::Element;
1368
1369    /// Numeric cast to another vector type, matching the semantics of Rust's
1370    /// `as` operator on the underlying scalar elements **for in-range, finite
1371    /// inputs**.
1372    ///
1373    /// Lane count is preserved; only the element type changes. The cast may
1374    /// be widening, narrowing, signed/unsigned, or float/int.
1375    ///
1376    /// Float-to-int lanes that are NaN or out of the destination's range
1377    /// produce a backend-defined value (x86 hardware conversions return the
1378    /// "indefinite" integer, `INT::MIN`, where scalar `as` would saturate).
1379    /// For exact `as` semantics on every input (NaN gives 0, out-of-range
1380    /// clamps) use [`saturating_cast`](Self::saturating_cast).
1381    ///
1382    /// The `strict_ieee754` feature points every **float-source** cast at the
1383    /// saturating implementation, so the two agree under it. Integer sources
1384    /// are left alone, deliberately: `as` wraps for int-to-int and so does
1385    /// `cast`, so redirecting them would clamp where the language wraps.
1386    #[inline(always)] fn cast<INTO>(self) -> INTO
1387    where
1388        INTO: CastVector<Self>,
1389    {
1390        INTO::cast_from(self)
1391    }
1392
1393    /// Fast numeric cast to another vector type.
1394    ///
1395    /// Equivalent to [`cast`](Self::cast) when the backend has no faster path,
1396    /// but may relax IEEE corner cases (NaN propagation, out-of-range
1397    /// float-to-int handling) in exchange for fewer instructions.
1398    ///
1399    /// Use [`cast`](Self::cast) when you need the documented `as` semantics
1400    /// exactly; use this when you have already ruled out problematic inputs.
1401    #[inline(always)] fn fast_cast<INTO>(self) -> INTO
1402    where
1403        INTO: CastVector<Self>,
1404    {
1405        INTO::fast_cast_from(self)
1406    }
1407
1408    /// Reinterpret the bits of this vector as another vector type of the same
1409    /// size and lane count.
1410    ///
1411    /// This is a zero-cost transmute; no conversion is performed. Typical use
1412    /// is moving between a float vector and its integer "bits" vector for
1413    /// bit-level manipulation.
1414    #[inline(always)] fn into_bits<INTO>(self) -> INTO
1415    where
1416        INTO: BitCastVector<Self>,
1417    {
1418        INTO::from_bits(self)
1419    }
1420
1421    /// Cast that saturates (clamps) out-of-range values to the destination
1422    /// element range, rather than wrapping (integers) or producing a
1423    /// backend-defined value (float-to-int) like [`cast`](Self::cast).
1424    ///
1425    /// Distinct from [`cast`](Self::cast) for narrowing, same-signedness integer
1426    /// conversions (`i64 -> ... -> i8`, `u64 -> ... -> u8`) and for every
1427    /// float-to-int pair at a given lane count (`f32`/`f64` into any of
1428    /// `i8`/`i16`/`i32`/`i64` and their unsigned forms), where it has exact Rust
1429    /// `as` semantics. NaN gives 0, out-of-range clamps to MIN/MAX.
1430    ///
1431    /// Every other conversion resolves too, falling through to
1432    /// [`cast`](Self::cast) because it has no separate saturating lowering.
1433    /// That is exact for widening conversions, which lose nothing. It is *not*
1434    /// what the name suggests for sign-changing integer casts, which wrap:
1435    /// there is no saturating `i32 -> u32`, so ask for [`cast`](Self::cast)
1436    /// and say what you meant.
1437    #[inline(always)] fn saturating_cast<INTO>(self) -> INTO
1438    where
1439        INTO: CastVector<Self>,
1440    {
1441        INTO::saturating_cast_from(self)
1442    }
1443}
1444
1445/// Bitwise operations over the lanes of a vector: `&`, `|`, `^`, `!`,
1446/// `bitandnot`, and the arbitrary three-input [`ternlog`](Self::ternlog).
1447///
1448/// Implemented by integer and mask vectors. Float vectors have no direct bitwise
1449/// ops, so reach their bits through [`FloatVectorWithBits`] first.
1450///
1451/// Note that `a.bitandnot(b)` is `a & !b` at this layer.
1452#[rustfmt::skip] #[thermite_macros::vector_trait]
1453#[diagnostic::on_unimplemented(
1454    message = "`{Self}` does not support bitwise vector operations",
1455    label = "no `&`, `|`, `^`, `!`, andnot, or ternlog",
1456    note = "`BitwiseVector` is implemented by integer and mask vectors. Floating-point vectors have no direct bitwise ops; reach their bits via `FloatVectorWithBits` (`.to_bits()` / reinterpret) first."
1457)]
1458pub trait BitwiseVector:
1459    GenericVector
1460    + ops::BitAndMasked<Self::Mask, Self, Output = Self>
1461    + ops::BitAndAssignMasked<Self::Mask, Self>
1462    + ops::BitAndNotMasked<Self::Mask, Self, Output = Self>
1463    + ops::BitAndNotAssignMasked<Self::Mask, Self>
1464    + ops::BitOrMasked<Self::Mask, Self, Output = Self>
1465    + ops::BitOrAssignMasked<Self::Mask, Self>
1466    + ops::BitXorMasked<Self::Mask, Self, Output = Self>
1467    + ops::BitXorAssignMasked<Self::Mask, Self>
1468    + ops::NotMasked<Self::Mask, Output = Self>
1469{
1470    /// Computes an arbitrary bitwise boolean function of three inputs (`a`, `b`, `c`)
1471    /// based on the truth table specified by `IMM`.
1472    ///
1473    /// This function is a "programmable logic gate". It applies the logic defined in `IMM`
1474    /// to every bit of the inputs in parallel.
1475    ///
1476    /// # How to Calculate `IMM`
1477    /// The easiest way to find the correct `IMM` value is to perform your desired boolean
1478    /// logic on these three specific "Magic Constants":
1479    ///
1480    /// * **A** = `0xF0` (Binary `11110000`)
1481    /// * **B** = `0xCC` (Binary `11001100`)
1482    /// * **C** = `0xAA` (Binary `10101010`)
1483    ///
1484    /// ## Example: `(A OR B) XOR C`
1485    /// 1. `A | B` = `0xF0 | 0xCC` = `0xFC`
1486    /// 2. `Result ^ C` = `0xFC ^ 0xAA` = `0x56`
1487    /// 3. Therefore, `IMM = 0x56`.
1488    ///
1489    /// You can also use the [`ternlog_imm!`](crate::ternlog_imm) macro to compute
1490    /// this at compile time.
1491    ///
1492    /// # Visualization using Disjunction Normal Form (DNF)
1493    /// The constants `0xF0`, `0xCC`, and `0xAA` simply form a parallel truth table
1494    /// for all 8 possible combinations of 3 bits:
1495    ///
1496    /// |  A  |  B  |  C  |  Bit Index  |  Term Logic (Minterm) |
1497    /// |:---:|:---:|:---:|:-----------:|:---------------------:|
1498    /// |  0  |  0  |  0  |      0      | ~A & ~B & ~C          |
1499    /// |  0  |  0  |  1  |      1      | ~A & ~B &  C          |
1500    /// |  0  |  1  |  0  |      2      | ~A &  B & ~C          |
1501    /// |  0  |  1  |  1  |      3      | ~A &  B &  C          |
1502    /// |  1  |  0  |  0  |      4      |  A & ~B & ~C          |
1503    /// |  1  |  0  |  1  |      5      |  A & ~B &  C          |
1504    /// |  1  |  1  |  0  |      6      |  A &  B & ~C          |
1505    /// |  1  |  1  |  1  |      7      |  A &  B &  C          |
1506    ///
1507    /// If `IMM = 0x88` (Bit 3 and 7 set), the logic is:
1508    /// - Bit 3 (0, 1, 1): `~A & B & C`
1509    /// - Bit 7 (1, 1, 1): `A & B & C`
1510    ///
1511    /// As raw DNF, this becomes: `(~A & B & C) | (A & B & C)`.\
1512    /// `~A` and `A` cancel out, simplifying to `B & C`.
1513    ///
1514    /// For each bit set in IMM, we effectively bitwise-OR each corresponding minterm.
1515    ///
1516    /// # Common Immediate Values
1517    /// | Logic | Immediate | Description |
1518    /// | :--- | :--- | :--- |
1519    /// | `A ^ B ^ C` | `0x96` | **3-Way XOR** (Parity) |
1520    /// | `(A & B) OR (~A & C)` | `0xCA` | **Bitwise Select** (If A=1 use B, else use C) |
1521    /// | `(A & B) OR (A & C) OR (B & C)` | `0xE8` | **Majority** (True if 2+ inputs are 1) |
1522    /// | `A OR B OR C` | `0xFE` | **3-Way OR** |
1523    /// | `A ? B : 0` | `0xA0` | **Mask** (A & B) |
1524    ///
1525    /// # Performance Note
1526    /// Since `IMM` is a compile-time constant, the compiler will optimize this function
1527    /// into the most efficient sequence of native instructions (AND, OR, XOR, NOT)
1528    /// for your specific architecture. If using AVX512, there actually exists a single
1529    /// instruction for this.
1530    ///
1531    /// Gate on [`HAS_NATIVE_TERNLOG`](Self::HAS_NATIVE_TERNLOG) when choosing
1532    /// between a ternlog bit assembly and a `select`/blend chain.
1533    #[conditional] fn ternlog<const IMM: i32>(a: Self, b: Self, c: Self) -> Self;
1534
1535    /// Whether [`ternlog`](Self::ternlog) is a single native instruction
1536    /// (AVX-512 `vpternlog{d,q}`), forwarded from
1537    /// [`BitwiseRegister::HAS_NATIVE_TERNLOG`](crate::register::BitwiseRegister::HAS_NATIVE_TERNLOG).
1538    ///
1539    /// Both paths compute the same function, so this only selects a lowering:
1540    /// one instruction where the hardware has ternary logic, up to eight DNF
1541    /// terms of AND/ANDNOT/OR where it does not. Fork on it when the
1542    /// alternative to a ternlog assembly is a `blendv`-style select chain -
1543    /// below AVX-512 the blends win (measured on znver3 in `ldexp`'s checked
1544    /// tail: 3.8 cyc/iter for blends against 5.8 for ternlogs), while a native
1545    /// ternlog makes the bit assembly strictly cheaper.
1546    const HAS_NATIVE_TERNLOG: bool;
1547
1548    /// Two-input version of [`ternlog`](Self::ternlog).
1549    ///
1550    /// Computes an arbitrary bitwise boolean function of two inputs (`a`, `b`)
1551    /// based on the 4-bit truth table specified by the low nibble of `IMM`.
1552    /// Bit `i` of `IMM` selects the output when `(a, b)` equals the binary
1553    /// representation of `i`. As with `ternlog`, the magic constants are
1554    /// `A = 0xC` (`1100`) and `B = 0xA` (`1010`); evaluate your desired logic
1555    /// against them to obtain `IMM`. For example, `A & B == 0x8`, `A | B == 0xE`,
1556    /// `A ^ B == 0x6`, `!A == 0x3`.
1557    ///
1558    /// Since `IMM` is a compile-time constant, the compiler lowers this to
1559    /// the most efficient native instruction sequence for the target ISA.
1560    #[conditional] fn bilog<const IMM: i32>(a: Self, b: Self) -> Self;
1561}
1562
1563/// Shifts and rotates over the lanes of an integer vector, by an immediate, by a
1564/// runtime scalar, or by a per-lane count.
1565///
1566/// `<<` and `>>` are the operator forms. **`>>` is a logical shift even on a
1567/// signed vector**, since the operator traits are shared with the unsigned
1568/// vectors. Sign-filling shifts live on [`SignedIntegerVector`] as
1569/// [`srai`](SignedIntegerVector::srai) / [`sra`](SignedIntegerVector::sra) /
1570/// [`srav`](SignedIntegerVector::srav).
1571///
1572/// Per-lane variable shifts ([`shlv`](Self::shlv) and friends) are one
1573/// instruction where the ISA has them (AVX2 `vpsllvd`) and a lane walk where it
1574/// does not, which [`HAS_TRUE_SHIFTV`](Self::HAS_TRUE_SHIFTV) reports.
1575#[rustfmt::skip] #[thermite_macros::vector_trait]
1576#[diagnostic::on_unimplemented(
1577    message = "`{Self}` does not support bit-shift vector operations",
1578    label = "no `<<`, `>>`, rotate, or byte-shift",
1579    note = "`BitshiftVector` is implemented by integer vectors (`Vector<i32>`, `Vector<u8>`, `i32xN`, ...). Float and mask vectors do not have shifts."
1580)]
1581pub trait BitshiftVector:
1582    BitwiseVector
1583    + ops::ShrMasked<Self::Mask, Self::Unsigned, Output = Self>
1584    + ops::ShrAssignMasked<Self::Mask, Self::Unsigned>
1585    + ops::ShlMasked<Self::Mask, Self::Unsigned, Output = Self>
1586    + ops::ShlAssignMasked<Self::Mask, Self::Unsigned>
1587    + ops::ShrMasked<Self::Mask, u32, Output = Self>
1588    + ops::ShrAssignMasked<Self::Mask, u32>
1589    + ops::ShlMasked<Self::Mask, u32, Output = Self>
1590    + ops::ShlAssignMasked<Self::Mask, u32>
1591{
1592    /// `true` if the backend has a true per-lane variable shift instruction
1593    /// (e.g. AVX2 `vpsllvd`). When `false`, [`shlv`](Self::shlv) /
1594    /// [`shrv`](Self::shrv) are emulated and may be slower than splatting a
1595    /// scalar shift count through [`shli`](Self::shli) / [`shri`](Self::shri).
1596    const HAS_TRUE_SHIFTV: bool;
1597
1598    /// `true` if the backend can byte-shift the entire vector as a single
1599    /// large integer at register widths above 128 bits without lane-boundary
1600    /// stitching. When `false`, [`bshli`](Self::bshli) / [`bshri`](Self::bshri)
1601    /// on wider vectors are emulated via shuffles.
1602    const HAS_WIDE_BYTE_SHIFTS: bool;
1603
1604    /// Treats the entire vector as a single large integer and shifts left by the immediate value
1605    /// number of BYTES. Not bits, bytes.
1606    ///
1607    /// Bits shifted out at the high end are discarded; the low end is zero-filled.
1608    #[conditional] fn bshli<const I: i32>(self) -> Self;
1609
1610    /// Treats the entire vector as a single large integer and shifts right by the immediate value
1611    /// number of BYTES. Not bits, bytes.
1612    ///
1613    /// Bits shifted out at the low end are discarded; the high end is zero-filled.
1614    #[conditional] fn bshri<const I: i32>(self) -> Self;
1615
1616    /// For each lane in the vector, shift left by the immediate value.
1617    #[conditional] fn shli<const I: i32>(self) -> Self;
1618
1619    /// For each lane in the vector, shift right by the immediate value.
1620    #[conditional] fn shri<const I: i32>(self) -> Self;
1621
1622    /// For each lane in the vector, shift left by the given value.
1623    #[conditional] fn shlv(self, counts: Self::Unsigned) -> Self;
1624
1625    /// For each lane in the vector, shift right by the given value.
1626    #[conditional] fn shrv(self, counts: Self::Unsigned) -> Self;
1627
1628    /// For each element in the vector, rotate the bits to the left by the given
1629    /// number of bits.
1630    #[conditional] fn rol(self, shift: u32) -> Self;
1631    /// For each element in the vector, rotate the bits to the right by the given
1632    /// number of bits.
1633    #[conditional] fn ror(self, shift: u32) -> Self;
1634    /// For each element in the vector, rotate the bits to the left by the immediate
1635    /// value number of bits.
1636    #[conditional] fn roli<const I: i32>(self) -> Self;
1637    /// For each element in the vector, rotate the bits to the right by the immediate
1638    /// value number of bits.
1639    #[conditional] fn rori<const I: i32>(self) -> Self;
1640
1641    /// For each element in the vector, rotate the bits to the left by the given
1642    /// number of bits in the corresponding lane of `counts`.
1643    #[conditional] fn rolv(self, counts: Self::Unsigned) -> Self;
1644
1645    /// For each element in the vector, rotate the bits to the right by the given
1646    /// number of bits in the corresponding lane of `counts`.
1647    #[conditional] fn rorv(self, counts: Self::Unsigned) -> Self;
1648
1649    /// For each element in the vector, reverse the bits of that element.
1650    #[conditional] fn reverse_bits(self) -> Self;
1651}
1652
1653/// Per-lane numeric conversion between vector types.
1654///
1655/// Implementing `CastVector<FROM>` for `Self` means a `FROM` value can be
1656/// converted into `Self` with the same semantics as Rust's `as` operator on
1657/// the underlying scalar elements. Most users should call
1658/// [`GenericVector::cast`] rather than these methods directly.
1659///
1660/// # Float to int
1661///
1662/// Float to int matches `as` for in-range finite lanes, truncating toward zero.
1663/// A NaN or out-of-range lane gets a **backend-defined** value instead. x86's
1664/// hardware conversions hand back the "indefinite" integer (`INT::MIN`) for
1665/// every such lane, where scalar `as` gives 0 for NaN and clamps the rest.
1666///
1667/// The fixup is not free. `f32x4 -> i32x4` is one `cvttps2dq`, and the exact
1668/// form is 5 instructions (a compare against 2^31, an unordered compare, an XOR
1669/// and an ANDNOT on top of it). A kernel that has already bounded its inputs
1670/// would pay that on every cast, so `cast` keeps the bare conversion.
1671///
1672/// [`saturating_cast_from`](Self::saturating_cast_from), reached through
1673/// [`GenericVector::saturating_cast`], is the exact form, and covers every
1674/// float-to-int pair at a given lane count. `strict_ieee754` points
1675/// float-source `cast_from` at it too, so the two agree under that feature and
1676/// every such cast pays the 5 instructions.
1677///
1678/// Integer sources are left alone by that feature, deliberately. `as` wraps for
1679/// int-to-int, which is already what `cast_from` does, so redirecting them would
1680/// clamp where the language wraps.
1681pub trait CastVector<FROM: Sized>: Sized {
1682    /// Convert a vector of type `FROM` into `Self`, lane-by-lane, using `as`
1683    /// semantics on each element. See the trait docs for what float-to-int
1684    /// does with NaN and out-of-range lanes.
1685    fn cast_from(from: FROM) -> Self;
1686
1687    /// Convert this vector into a vector of type `FROM`, lane-by-lane.
1688    fn cast_into(self) -> FROM;
1689
1690    /// Convert lane-by-lane, clamping out-of-range values to `Self`'s element
1691    /// range rather than wrapping (integers) or producing a backend-defined
1692    /// value (float to int).
1693    ///
1694    /// Float to int is exactly Rust's `as` here. NaN gives 0, and anything out
1695    /// of range clamps to the destination MIN/MAX. Meaningful for narrowing
1696    /// same-sign integer pairs and for every float-to-int pair; conversions with
1697    /// no distinct saturating lowering (widening, sign-changing, float to float)
1698    /// fall through to [`cast_from`](Self::cast_from), which for the widening
1699    /// cases is already exact.
1700    #[inline(always)]
1701    fn saturating_cast_from(from: FROM) -> Self {
1702        Self::cast_from(from)
1703    }
1704
1705    /// Like [`cast_from`](Self::cast_from), but may take a faster path that
1706    /// relaxes IEEE corner cases. See [`GenericVector::fast_cast`].
1707    ///
1708    /// Float-to-int keeps its narrow domain in every configuration,
1709    /// `strict_ieee754` included. This is the operation whose out-of-range
1710    /// behavior is unspecified by definition, so that feature has nothing to
1711    /// tighten here.
1712    #[inline(always)]
1713    fn fast_cast_from(from: FROM) -> Self {
1714        Self::cast_from(from)
1715    }
1716
1717    /// Like [`cast_into`](Self::cast_into), but may take a faster path that
1718    /// relaxes IEEE corner cases. See [`GenericVector::fast_cast`].
1719    #[inline(always)]
1720    fn fast_cast_into(self) -> FROM {
1721        Self::cast_into(self)
1722    }
1723}
1724
1725/// Zero-cost bit-level reinterpretation between vector types of the same
1726/// size and lane count.
1727///
1728/// Unlike [`CastVector`], no numeric conversion is performed: the underlying
1729/// bits are reinterpreted as the destination element type. Typical use is
1730/// moving between a float vector and its integer "bits" vector.
1731pub trait BitCastVector<FROM: Sized>: Sized {
1732    /// Reinterpret the bit pattern of `bits` as a value of `Self`.
1733    fn from_bits(bits: FROM) -> Self;
1734}
1735
1736/// A `u16`/`u8` integer vector reinterpreted as a vector of *packed floats* (format `S`: fp16,
1737/// bfloat16, the fp8 variants, ...), transcodable to and from the wider `f32` vector `F` of the
1738/// same lane count.
1739///
1740/// This is the vector-layer mirror of
1741/// [`PackedFloatRegister`](crate::register::PackedFloatRegister): `Self` is the `Vector<u16/u8
1742/// register>` and `F` is the matching `Vector<f32 register>`. Both directions are exact for the
1743/// decode (every value of these sub-`f32` formats is representable in `f32`) and round-to-nearest
1744/// for the encode; backends use hardware (F16C `vcvtph2ps`) where available and a generic
1745/// branchless fallback otherwise.
1746///
1747/// Blanket-implemented for every `Vector<R>` whose register implements `PackedFloatRegister<S,
1748/// FR>`, so e.g. `u16x8<S>: PackedFloatVector<Fp16, f32x8<S>>` holds wherever the register does.
1749///
1750/// ```
1751/// # use thermite::prelude::*;
1752/// # use thermite::element::float::spec::Fp16;
1753/// # use thermite::vector::PackedFloatVector;
1754/// fn widen<U, F>(halves: U) -> F
1755/// where
1756///     U: PackedFloatVector<Fp16, F>,
1757/// {
1758///     halves.unpack()
1759/// }
1760/// ```
1761pub trait PackedFloatVector<S: crate::element::float::spec::FloatSpec, F>: GenericVector {
1762    /// Encode the `f32` vector `values` into this packed format (round to nearest, ties to even;
1763    /// overflow / non-finite handled per the format `S`).
1764    fn pack(values: F) -> Self;
1765
1766    /// Decode this packed-float vector into the `f32` vector it represents (exact).
1767    fn unpack(self) -> F;
1768}
1769
1770/// A `u8` vector whose absolute differences can be summed in groups of 2 byte-lanes into
1771/// the `u16` vector `W` (same total width, `LANES / 2` output lanes).
1772///
1773/// Vector-layer mirror of [`Sad16Register`](crate::register::Sad16Register);
1774/// blanket-implemented for every `Vector<R>` whose register implements it. Each output
1775/// lane is at most `510`. There is no accumulating form - a `u16` lane saturates after
1776/// ~128 accumulations; use [`Sad32Vector`] / [`Sad64Vector`] to reduce over a long run.
1777pub trait Sad16Vector<W>: GenericVector {
1778    /// Sum of absolute differences over each aligned pair of byte lanes.
1779    fn sad16(self, other: Self) -> W;
1780}
1781
1782/// A `u8` vector whose absolute differences can be summed in groups of 4 byte-lanes into
1783/// the `u32` vector `W` (same total width, `LANES / 4` output lanes).
1784///
1785/// Vector-layer mirror of [`Sad32Register`](crate::register::Sad32Register). Each output
1786/// lane is at most `1020`, so [`sad32_accum`](Self::sad32_accum) absorbs ~4.2e6
1787/// accumulations before overflow.
1788pub trait Sad32Vector<W>: GenericVector {
1789    /// Sum of absolute differences over each aligned group of 4 byte lanes.
1790    fn sad32(self, other: Self) -> W;
1791
1792    /// `acc + self.sad32(other)` - the accumulate step of a blocked SAD loop.
1793    fn sad32_accum(self, acc: W, other: Self) -> W;
1794}
1795
1796/// A `u8` vector whose absolute differences can be summed in groups of 8 byte-lanes into
1797/// the `u64` vector `W` (same total width, `LANES / 8` output lanes) - x86 `PSADBW`
1798/// semantics.
1799///
1800/// Vector-layer mirror of [`Sad64Register`](crate::register::Sad64Register). The `u64`
1801/// lanes are accumulation headroom (each result is at most `2040`), so the intended shape
1802/// of a byte-buffer reduction is to [`sad64_accum`](Self::sad64_accum) through the loop
1803/// and reduce horizontally exactly once at the end:
1804///
1805/// ```ignore
1806/// let mut acc = W::ZERO;
1807/// for (a, b) in blocks { acc = a.sad64_accum(acc, b); }
1808/// let total = acc.sum_elements();
1809/// ```
1810pub trait Sad64Vector<W>: GenericVector {
1811    /// Sum of absolute differences over each aligned group of 8 byte lanes.
1812    fn sad64(self, other: Self) -> W;
1813
1814    /// `acc + self.sad64(other)` - the accumulate step of a blocked SAD loop.
1815    fn sad64_accum(self, acc: W, other: Self) -> W;
1816}
1817
1818/// Lanes of a vector partitioned into groups of equal value, produced by
1819/// [`group_by_value`](PartialOrdVector::group_by_value).
1820///
1821/// Each call to [`next_group`](Self::next_group) yields one distinct value and
1822/// the mask of lanes holding it; groups come out in order of first occurrence,
1823/// and every selected lane is yielded exactly once. That turns a divergent
1824/// packet, whose lanes want different work, into a short sequence of uniform
1825/// sub-packets.
1826///
1827/// The inherent [`next_group`](Self::next_group) is the primary interface: a
1828/// plain `while let` loop needs no trait in scope and inlines predictably inside
1829/// `#[target_feature]` bodies. [`Iterator`] is implemented on top of it, so
1830/// `for` loops work too.
1831///
1832/// ```ignore
1833/// // Shade a ray packet one geometry at a time.
1834/// let mut groups = geom_ids.group_by_value(active);
1835/// while let Some((geom_id, lanes)) = groups.next_group() {
1836///     shade(geom_id, lanes);
1837/// }
1838/// ```
1839///
1840/// Cost is proportional to the number of *distinct* values, not the lane count:
1841/// roughly a broadcast, a compare, and two mask ops per group. A uniform packet
1842/// costs one iteration.
1843#[derive(Debug, Clone, Copy)]
1844pub struct ValueGroups<V: PartialOrdVector> {
1845    value: V,
1846    remaining: V::Mask,
1847}
1848
1849impl<V: PartialOrdVector> ValueGroups<V> {
1850    /// The next distinct value and the mask of remaining lanes holding it, or
1851    /// `None` once every selected lane has been yielded.
1852    #[inline(always)]
1853    pub fn next_group(&mut self) -> Option<(V::Element, V::Mask)> {
1854        let lane = self.remaining.first_set()?;
1855
1856        // `broadcastv` rather than `splat(extractv(..))`: one register op that
1857        // backends already specialize, instead of a lane -> scalar -> lane
1858        // round trip through memory.
1859        let group = self.remaining & self.value.cmp_eq(self.value.broadcastv(lane));
1860        let value = self.value.extractv(lane);
1861
1862        self.remaining = crate::vector::ops::BitAndNot::bitandnot(self.remaining, group);
1863
1864        Some((value, group))
1865    }
1866
1867    /// Lanes not yet yielded, so a caller can stop part-way and keep the rest.
1868    #[inline(always)]
1869    pub fn remaining(&self) -> V::Mask {
1870        self.remaining
1871    }
1872
1873    /// Whether every selected lane has been yielded.
1874    #[inline(always)]
1875    pub fn is_empty(&self) -> bool {
1876        self.remaining.none()
1877    }
1878}
1879
1880impl<V: PartialOrdVector> Iterator for ValueGroups<V> {
1881    type Item = (V::Element, V::Mask);
1882
1883    #[inline(always)]
1884    fn next(&mut self) -> Option<Self::Item> {
1885        self.next_group()
1886    }
1887}
1888
1889/// Per-lane comparison producing a [`Mask`](GenericVector::Mask).
1890///
1891/// Each comparison returns a mask whose lanes are `true` where the predicate
1892/// held for the corresponding lane pair and `false` otherwise. The mask can
1893/// then be used with [`select`](crate::mask::GenericMask::select),
1894/// `_c`/`_m`/`_z` masked variants, or reduced via
1895/// [`all`](crate::mask::GenericMask::all) /
1896/// [`any`](crate::mask::GenericMask::any).
1897///
1898/// For floating-point vectors, NaN compares unequal to everything, so e.g.
1899/// `cmp_lt(x, NaN)` is always `false`, matching the `<` operator on `f32`/`f64`.
1900#[diagnostic::on_unimplemented(
1901    message = "`{Self}` does not support lane-wise comparisons",
1902    label = "no `cmp_lt` / `cmp_le` / `cmp_gt` / `cmp_ge` / `cmp_eq` / `cmp_ne`",
1903    note = "`PartialOrdVector` turns lane-wise comparisons into a `Mask`; it is implemented by all numeric vectors (integer and float)."
1904)]
1905pub trait PartialOrdVector: GenericVector + PartialEq {
1906    /// Partition the lanes selected by `valid` into groups of equal value.
1907    ///
1908    /// See [`ValueGroups`] for the loop shape and cost. Pass
1909    /// `Self::Mask::TRUTHY` to group every lane.
1910    #[inline(always)]
1911    fn group_by_value(self, valid: Self::Mask) -> ValueGroups<Self> {
1912        ValueGroups {
1913            value: self,
1914            remaining: valid,
1915        }
1916    }
1917
1918    /// Lane-wise `self < other`.
1919    fn cmp_lt(self, other: Self) -> Self::Mask;
1920    /// Lane-wise `self <= other`.
1921    fn cmp_le(self, other: Self) -> Self::Mask;
1922    /// Lane-wise `self > other`.
1923    fn cmp_gt(self, other: Self) -> Self::Mask;
1924    /// Lane-wise `self >= other`.
1925    fn cmp_ge(self, other: Self) -> Self::Mask;
1926    /// Lane-wise `self == other`.
1927    fn cmp_eq(self, other: Self) -> Self::Mask;
1928    /// Lane-wise `self != other`.
1929    fn cmp_ne(self, other: Self) -> Self::Mask;
1930}
1931
1932/// Vectors that support arithmetic and comparison operations on their elements.
1933///
1934/// This trait sits between [`PartialOrdVector`] and the more specific
1935/// [`SignedVector`] / [`IntegerVector`] / [`FloatVector`] traits, and provides
1936/// the operator overloads (`+`, `-`, `*`, `/`, `%`, their `*Assign` variants,
1937/// and the masked `_c`/`_m`/`_z` forms via [`ops`]).
1938///
1939/// # Overflow semantics
1940///
1941/// **For integer element types, the basic arithmetic operators (`+`, `-`, `*`,
1942/// `/`, `%`) are wrapping on overflow.** This matches the behavior of every
1943/// SIMD ISA (`paddd`, `pmulld`, etc. all wrap silently) and avoids per-lane
1944/// panics inside vectorized loops. Concretely, on every backend including the
1945/// scalar reference backend, `Vector::<i32x4>::splat(i32::MAX) + Vector::ONE`
1946/// produces `i32::MIN` in every lane rather than panicking.
1947///
1948/// This is intentional and is **not affected by debug vs release builds**: the
1949/// scalar backend uses `wrapping_add` / `wrapping_sub` / `wrapping_mul`
1950/// internally, so the wrapping behavior is consistent across all build
1951/// configurations. If you need saturation or explicit wrapping naming, use
1952/// [`saturating_add`](IntegerVector::saturating_add) /
1953/// [`saturating_sub`](IntegerVector::saturating_sub), or the
1954/// `num_traits::WrappingAdd` / `WrappingSub` / `WrappingMul` impls.
1955///
1956/// Integer division (`/`, `%`) panics on division by zero, matching scalar
1957/// Rust. Float division by zero produces an infinity or NaN per IEEE 754.
1958///
1959/// For float element types, overflow simply produces an infinity per IEEE 754;
1960/// there is nothing to wrap.
1961#[rustfmt::skip] #[thermite_macros::vector_trait]
1962#[diagnostic::on_unimplemented(
1963    message = "`{Self}` does not support arithmetic vector operations",
1964    label = "no `+`, `-`, `*`, `/`, `%`, min/max, or FMA",
1965    note = "`NumericVector` is implemented by numeric vectors - integer (`Vector<i32>`, `i32xN`, ...) and float (`Vector<f32>`, `f32xN`, ...). Masks and bare scalars do not qualify.",
1966    note = "A bare `f32`/`f64` is not a vector: wrap it in `Vector::<f32>::splat(x)` first."
1967)]
1968pub trait NumericVector:
1969    PartialOrdVector<Element: num_traits::NumOps>
1970    + ops::AddMasked<Self::Mask, Self, Output = Self>
1971    + ops::AddAssignMasked<Self::Mask, Self>
1972    + ops::SubMasked<Self::Mask, Self, Output = Self>
1973    + ops::SubAssignMasked<Self::Mask, Self>
1974    + ops::MulMasked<Self::Mask, Self, Output = Self>
1975    + ops::MulAssignMasked<Self::Mask, Self>
1976    + ops::DivMasked<Self::Mask, Self, Output = Self>
1977    + ops::DivAssignMasked<Self::Mask, Self>
1978    + ops::RemMasked<Self::Mask, Self, Output = Self>
1979    + ops::RemAssignMasked<Self::Mask, Self>
1980    + ops::SquareMasked<Self::Mask, Output = Self>
1981    + num_traits::NumOps<Self>
1982    + num_traits::NumAssignOps<Self>
1983    + core::iter::Sum
1984    + core::iter::Product
1985{
1986    /// A vector of the value "0" in the element type.
1987    const ZERO: Self;
1988    /// A vector of the value "1" in the element type.
1989    const ONE: Self;
1990    /// A vector of the value "2" in the element type.
1991    const TWO: Self;
1992
1993    /// A vector of the minimum value the element type of this vector can represent.
1994    const MIN: Self;
1995    /// A vector of the maximum value the element type of this vector can represent.
1996    const MAX: Self;
1997
1998    /// Convert each lane to the companion signed integer type, with `as` semantics -
1999    /// round toward zero, saturating at the bounds, NaN to zero.
2000    ///
2001    /// This is the numeric conversion, *not* a bit reinterpretation; for the bit
2002    /// pattern of a float see [`GenericVector::into_bits`].
2003    ///
2004    /// # Why a method and not a `CastVector` bound
2005    ///
2006    /// A bound would have to be written either as `Self::Signed: CastVector<Self>`,
2007    /// whose impl `Self` type is an associated-type projection and so cannot be
2008    /// written at all, or as `Self: CastVector<Self::Signed>`, which collides with the
2009    /// blanket self-casts the composite types already carry. A method has no coherence
2010    /// surface and every implementor can simply provide it.
2011    fn to_signed_integer(self) -> Self::Signed;
2012
2013    /// Convert each lane from the companion signed integer type, with `as` semantics.
2014    ///
2015    /// For composite element types this produces a value with no imaginary part, no
2016    /// derivative and no error term: an integer carries none of those.
2017    fn from_signed_integer(v: Self::Signed) -> Self;
2018
2019    /// Convert each lane to the companion unsigned integer type, with `as` semantics.
2020    /// See [`to_signed_integer`](Self::to_signed_integer).
2021    fn to_unsigned_integer(self) -> Self::Unsigned;
2022
2023    /// Convert each lane from the companion unsigned integer type, with `as` semantics.
2024    /// See [`from_signed_integer`](Self::from_signed_integer).
2025    fn from_unsigned_integer(v: Self::Unsigned) -> Self;
2026
2027    /// Like [`to_signed_integer`](Self::to_signed_integer), but may relax IEEE corner
2028    /// cases (out-of-range and NaN inputs) for speed. Defaults to the exact form.
2029    #[inline(always)]
2030    fn fast_to_signed_integer(self) -> Self::Signed {
2031        self.to_signed_integer()
2032    }
2033
2034    /// Like [`to_unsigned_integer`](Self::to_unsigned_integer), but may relax IEEE
2035    /// corner cases. Defaults to the exact form.
2036    #[inline(always)]
2037    fn fast_to_unsigned_integer(self) -> Self::Unsigned {
2038        self.to_unsigned_integer()
2039    }
2040
2041    /// For each element in the vector, return a mask indicating whether that element is zero.
2042    fn is_zero(self) -> Self::Mask;
2043
2044    /// Returns `true` if all elements in the vector are zero, `false` otherwise.
2045    ///
2046    /// This can often be more performant than naive comparisons or even `is_zero().all()`
2047    fn is_all_zero(self) -> bool;
2048
2049    /// Return the minimum of two vectors, element-wise.
2050    #[conditional] fn min(self, other: Self) -> Self;
2051
2052    /// Return the maximum of two vectors, element-wise.
2053    #[conditional] fn max(self, other: Self) -> Self;
2054
2055    /// Sort the lanes of this vector in `O` order.
2056    ///
2057    /// Backed by a sorting network where one exists for the lane count, and by
2058    /// a scalar compare-and-swap walk otherwise - see
2059    /// [`NumericRegister::sort_by`](crate::register::NumericRegister::sort_by),
2060    /// which this delegates to so a backend override is picked up here too.
2061    /// The direction is free; see [`crate::sort`].
2062    fn sort_by<O: crate::sort::SortOrder>(self) -> Self;
2063
2064    /// Sort the lanes of a **bitonic** vector in `O` order - one that rises then
2065    /// falls, or a rotation of one.
2066    ///
2067    /// Garbage in, garbage out on non-bitonic input. See
2068    /// [`NumericRegister::bitonic_clean_by`](crate::register::NumericRegister::bitonic_clean_by).
2069    fn bitonic_clean_by<O: crate::sort::SortOrder>(self) -> Self;
2070
2071    /// Sort the lanes ascending. Shorthand for
2072    /// [`sort_by::<Ascending>`](Self::sort_by).
2073    #[inline(always)]
2074    fn sort(self) -> Self {
2075        self.sort_by::<crate::sort::Ascending>()
2076    }
2077
2078    /// Sort the lanes of a **bitonic** vector ascending. Shorthand for
2079    /// [`bitonic_clean_by::<Ascending>`](Self::bitonic_clean_by).
2080    #[inline(always)]
2081    fn bitonic_clean(self) -> Self {
2082        self.bitonic_clean_by::<crate::sort::Ascending>()
2083    }
2084
2085    /// Clamps the elements of the vector between the given minimum and maximum values.
2086    fn clamp(self, min: Self, max: Self) -> Self;
2087
2088    /// Returns the minimum value in the vector.
2089    ///
2090    /// This operation has an `O(log2 n)` complexity to reduce.
2091    fn min_element(self) -> Self::Element;
2092    /// Returns the maximum value in the vector.
2093    ///
2094    /// This operation has an `O(log2 n)` complexity to reduce.
2095    fn max_element(self) -> Self::Element;
2096    /// Returns both the minimum and maximum values in the vector simultaneously.
2097    ///
2098    /// More efficient than calling [`min_element`](NumericVector::min_element) and
2099    /// [`max_element`](NumericVector::max_element) separately when both are needed.
2100    fn min_max_element(self) -> (Self::Element, Self::Element);
2101
2102    /// Returns the indices of the minimum and maximum elements in the vector, respectively.
2103    fn arg_minmax(self) -> (usize, usize);
2104
2105    /// Scales each element in the vector by the given factor.
2106    ///
2107    /// While semantically equivalent to `self * Self::splat(factor)`, this method may be optimized
2108    /// better on certain architectures, such as GPUs.
2109    #[conditional] fn scale(self, factor: Self::Element) -> Self;
2110
2111    /// Sums adjacent lane pairs from `lo` and `hi`, returning a vector of the same width.
2112    ///
2113    /// Output: `[lo[0]+lo[1], lo[2]+lo[3], ..., hi[0]+hi[1], hi[2]+hi[3], ...]`
2114    ///
2115    /// The result is always in strict order: all pair sums from `lo` followed by all pair sums from `hi`.
2116    fn pairwise_sum(lo: Self, hi: Self) -> Self;
2117
2118    /// Like [`pairwise_sum`](NumericVector::pairwise_sum), but may return a relaxed (implementation-defined)
2119    /// lane ordering for performance. Treat this as if randomly shuffling the result of
2120    /// [`pairwise_sum`](NumericVector::pairwise_sum), with better performance than `pairwise_sum`.
2121    ///
2122    /// Prefer this if you are simply summing any adjacent pairs from `lo` and `hi`, and don't
2123    /// care about the exact ordering of the resulting sums.
2124    fn relaxed_pairwise_sum(lo: Self, hi: Self) -> Self;
2125
2126    /// Returns the sum of all elements in the vector.
2127    ///
2128    /// This operation has an `O(log2 n)` complexity to reduce.
2129    fn sum_elements(self) -> Self::Element;
2130
2131    /// Returns the product of all elements in the vector.
2132    ///
2133    /// This operation has an `O(log2 n)` complexity to reduce.
2134    fn prod_elements(self) -> Self::Element;
2135
2136    /// Inclusive forward prefix sum ("running total"): `out[i] = self[0] + .. + self[i]`.
2137    ///
2138    /// Unlike [`sum_elements`](Self::sum_elements), which collapses the register to one
2139    /// scalar, this keeps every partial sum in its own lane - the primitive behind
2140    /// bin offsets and stream-compaction write indices.
2141    ///
2142    /// `O(log2 LANES)` vector ops where the backend has a native cross-register
2143    /// [`align`](GenericVector::align), a sequential lane walk where it does not,
2144    /// chosen at compile time. For a scan over only some lanes, neutralise the rest
2145    /// first: `v.zz(mask).prefix_sum()`.
2146    ///
2147    /// ```
2148    /// use thermite::prelude::*;
2149    /// use thermite::backend::scalar::Scalar;
2150    ///
2151    /// let v = <thermite::simd::i32x4<Scalar>>::new([1, 2, 3, 4]);
2152    /// assert_eq!(v.prefix_sum().into_array(), [1, 3, 6, 10].into());
2153    /// assert_eq!(v.reverse_prefix_sum().into_array(), [10, 9, 7, 4].into());
2154    /// ```
2155    fn prefix_sum(self) -> Self;
2156
2157    /// Inclusive forward prefix minimum: `out[i] = min(self[0], .., self[i])`.
2158    ///
2159    /// See [`prefix_sum`](Self::prefix_sum) for the cost model. With NaN lanes, which
2160    /// operand wins is unspecified (as for [`min`](Self::min) itself); exact and
2161    /// backend-identical otherwise, infinities included.
2162    fn prefix_min(self) -> Self;
2163
2164    /// Inclusive forward prefix maximum: `out[i] = max(self[0], .., self[i])`.
2165    ///
2166    /// See [`prefix_min`](Self::prefix_min) for the NaN caveat.
2167    fn prefix_max(self) -> Self;
2168
2169    /// Inclusive reverse (suffix) sum: `out[i] = self[i] + .. + self[LANES-1]`.
2170    fn reverse_prefix_sum(self) -> Self;
2171
2172    /// Inclusive reverse (suffix) minimum: `out[i] = min(self[i], .., self[LANES-1])`.
2173    ///
2174    /// See [`prefix_min`](Self::prefix_min) for the NaN caveat.
2175    fn reverse_prefix_min(self) -> Self;
2176
2177    /// Inclusive reverse (suffix) maximum: `out[i] = max(self[i], .., self[LANES-1])`.
2178    ///
2179    /// See [`prefix_min`](Self::prefix_min) for the NaN caveat.
2180    fn reverse_prefix_max(self) -> Self;
2181
2182    /// Returns a vector whose every lane equals [`LANES`](GenericVector::LANES),
2183    /// converted into the element type.
2184    ///
2185    /// Equivalent to `Self::splat(Self::LANES as Self::Element)`. Useful for
2186    /// stepping an [`indexed`](Self::indexed) counter forward by one full
2187    /// vector's worth of lanes in tight loops.
2188    fn offset() -> Self;
2189
2190    /// Returns a vector where each lane holds its own index, cast to the
2191    /// element type: `[0, 1, 2, ..., LANES-1]`.
2192    ///
2193    /// This is the typical starting point for index-based vector loops. The
2194    /// counter can be advanced by adding [`offset`](Self::offset).
2195    fn indexed() -> Self;
2196}
2197
2198/// Vectors whose elements can represent negative values.
2199///
2200/// Adds negation, absolute value, sign extraction, and sign-conditional
2201/// selection on top of [`NumericVector`]. Implemented for signed integer and
2202/// floating-point vectors; not for unsigned integer vectors.
2203///
2204/// As with the base [`NumericVector`] operators, unary `-` on a signed integer
2205/// vector is **wrapping**: `-Vector::<i32x4>::splat(i32::MIN)` returns
2206/// `i32::MIN` in every lane rather than panicking.
2207// TODO: Add back in some kind of `Signed` trait requirement for Element?
2208#[rustfmt::skip] #[thermite_macros::vector_trait]
2209#[diagnostic::on_unimplemented(
2210    message = "`{Self}` is not a signed SIMD vector",
2211    label = "no `abs`, `signum`, `copysign`, or unary `-`",
2212    note = "`SignedVector` is implemented by signed integer and floating-point vectors. Unsigned integer vectors (`Vector<u32>`, `u8xN`, ...) are not signed."
2213)]
2214pub trait SignedVector: NumericVector + ops::NegMasked<Self::Mask, Output = Self> {
2215    /// A vector of the value "-1" in the element type.
2216    const NEG_ONE: Self;
2217
2218    /// A vector of the smallest positive (non-zero) value in the element type.
2219    const MIN_POSITIVE: Self;
2220
2221    /// Take the absolute value of the vector, element-wise.
2222    #[conditional] fn abs(self) -> Self;
2223
2224    /// For each element in the vector, return a new vector
2225    /// where each element is either -1 or +1 depending
2226    /// on the sign of the element.
2227    ///
2228    /// For integers, this will also return zero (0) if the
2229    /// element is zero. This matches Rust's behavior for integer
2230    /// `signum`. Floats remain only -1 or +1.
2231    fn signum(self) -> Self;
2232
2233    /// For each element in the vector, set the sign of that
2234    /// element to the sign of the corresponding element in the other vector.
2235    #[conditional] fn copysign(self, sign: Self) -> Self;
2236
2237    /// For each element in the vector, return a mask indicating
2238    /// whether that element is negative.
2239    fn is_positive(self) -> Self::Mask;
2240
2241    /// For each element in the vector, return a mask indicating
2242    /// whether that element is positive.
2243    fn is_negative(self) -> Self::Mask;
2244
2245    /// Based on if self is negative, select between `if_neg` and `if_pos`.
2246    fn select_negative(self, if_neg: Self, if_pos: Self) -> Self;
2247}
2248
2249/// Vectors of integer elements.
2250///
2251/// Adds bitwise shifts (via [`BitshiftVector`]), bit-counting, saturating
2252/// arithmetic, branchfree integer division helpers, and exposes the type of
2253/// the per-divider precomputed structures used for vectorized division.
2254///
2255/// # Wrapping arithmetic
2256///
2257/// The basic operators (`+`, `-`, `*`, their assigning forms, and unary `-`
2258/// for signed integer vectors) **wrap on overflow** on every backend, in both
2259/// debug and release builds. See [`NumericVector`] for the rationale. The
2260/// `num_traits::WrappingAdd` / `WrappingSub` / `WrappingMul` impls are simply
2261/// renames of the operator forms; for explicit saturation use
2262/// [`saturating_add`](Self::saturating_add) /
2263/// [`saturating_sub`](Self::saturating_sub).
2264///
2265/// # Reductions
2266///
2267/// Horizontal reductions ([`sum_elements`](NumericVector::sum_elements),
2268/// [`prod_elements`](NumericVector::prod_elements), [`wrapping_sum`](Self::wrapping_sum),
2269/// [`wrapping_prod`](Self::wrapping_prod)) all wrap on overflow.
2270#[rustfmt::skip] #[thermite_macros::vector_trait]
2271#[diagnostic::on_unimplemented(
2272    message = "`{Self}` is not an integer SIMD vector",
2273    label = "not an integer vector",
2274    note = "`IntegerVector` is implemented by integer vectors (`Vector<i32>`, `Vector<u8>`, `i32xN`, ...). Float vectors implement `FloatVector` instead; convert with `.to_int()` or a cast."
2275)]
2276pub trait IntegerVector:
2277    NumericVector<Element: Denominator>
2278    + BitshiftVector
2279    + ops::DivMasked<Self::Mask, Self::Divider, Output = Self>
2280    + ops::DivMasked<Self::Mask, Self::BranchfreeDivider, Output = Self>
2281    // TODO: Some of these might interfere with the methods of this trait,
2282    // adding ambiguity. See what we can do about that.
2283    + num_traits::Saturating + num_traits::SaturatingAdd
2284    + num_traits::SaturatingSub + num_traits::WrappingMul
2285    + num_traits::WrappingAdd + num_traits::WrappingSub
2286{
2287    /// Precomputed scalar divider used by per-lane division against a
2288    /// runtime-known but loop-invariant divisor. See [`crate::Divider`].
2289    type Divider: Copy;
2290    /// Branchfree variant of [`Divider`](Self::Divider). Slightly slower for
2291    /// some divisors but always emits straight-line code with no conditional
2292    /// branches, which is what you want inside a hot SIMD loop.
2293    type BranchfreeDivider: Copy;
2294    /// Precomputed per-lane divider produced by [`to_divider`](Self::to_divider).
2295    /// Used when each lane needs a different (but loop-invariant) divisor.
2296    type VectorizedDivider: Copy;
2297
2298    /// Multiply two vectors lane-wise and return the *high* half of each
2299    /// double-width product.
2300    ///
2301    /// For signed `i32` lanes the result is `(a as i64 * b as i64) >> 32`;
2302    /// for unsigned `u32` it is the same with `u64`. Together with
2303    /// [`mullo`](Self::mullo) this gives the full double-width product
2304    /// without widening the vector type.
2305    #[conditional] fn mulhi(self, other: Self) -> Self;
2306
2307    /// Multiply two vectors lane-wise and return the *low* half of each
2308    /// product, with wrapping on overflow.
2309    ///
2310    /// This is bit-identical to the `*` operator on integer vectors; the
2311    /// dedicated method exists because some ISAs have specialized
2312    /// low-half-only multiply instructions worth emitting directly.
2313    #[conditional] fn mullo(self, other: Self) -> Self;
2314
2315    // fn wrapping_add(self, other: Self) -> Self;
2316    // fn wrapping_sub(self, other: Self) -> Self;
2317    // fn wrapping_mul(self, other: Self) -> Self;
2318
2319    /// Per-lane saturating addition: instead of wrapping, the result is
2320    /// clamped to the element type's range (`MIN`..=`MAX`) on overflow.
2321    #[conditional] fn saturating_add(self, other: Self) -> Self;
2322
2323    /// Per-lane saturating subtraction: instead of wrapping, the result is
2324    /// clamped to the element type's range (`MIN`..=`MAX`) on overflow.
2325    #[conditional] fn saturating_sub(self, other: Self) -> Self;
2326
2327    /// Horizontal sum of all lanes, wrapping on overflow.
2328    ///
2329    /// Equivalent to [`sum_elements`](NumericVector::sum_elements) on integer
2330    /// vectors; the explicit name documents the wrapping behavior at the
2331    /// callsite.
2332    #[conditional] fn wrapping_sum(self) -> Self::Element;
2333
2334    /// Horizontal product of all lanes, wrapping on overflow.
2335    ///
2336    /// Equivalent to [`prod_elements`](NumericVector::prod_elements); the
2337    /// explicit name documents the wrapping behavior at the callsite.
2338    #[conditional] fn wrapping_prod(self) -> Self::Element;
2339
2340    /// Build a [`Divider`](Self::Divider) for a single scalar divisor `d`,
2341    /// suitable for repeatedly dividing many vectors by the same `d`.
2342    ///
2343    /// Construction is `O(1)` but non-trivial; build once outside the hot
2344    /// loop, then use `vec / divider` inside.
2345    fn create_divider(d: Self::Element) -> Self::Divider;
2346
2347    /// Build a [`BranchfreeDivider`](Self::BranchfreeDivider) for a single
2348    /// scalar divisor `d`. Prefer this over [`create_divider`](Self::create_divider)
2349    /// inside tight SIMD loops where conditional branches would hurt
2350    /// throughput.
2351    fn create_branchfree_divider(d: Self::Element) -> Self::BranchfreeDivider;
2352
2353    /// Use this vector as the denominators for a vectorized division operation.
2354    ///
2355    /// This creates a `VectorDivider` which can then be used to perform
2356    /// vectorized integer division with the `Div` trait. Note that for unsigned
2357    /// integer types, `1` is not a valid denominator and will cause a panic.
2358    ///
2359    /// This operation itself is NOT vectorized and is `O(n)` in the number of lanes.
2360    /// It is designed to be calculated once and then reused for multiple division operations.
2361    ///
2362    /// # Panics
2363    ///
2364    /// If unsigned, integer values of `1` present in the vector
2365    /// denominators will cause a panic.
2366    fn to_divider(self) -> Self::VectorizedDivider;
2367
2368    /// For each element in the vector, count the number of bits that are set to 1.
2369    #[conditional] fn count_ones(self) -> Self;
2370    /// For each element in the vector, count the number of bits that are set to 0.
2371    #[conditional] fn count_zeros(self) -> Self;
2372    /// For each element in the vector, count the number of leading ones.
2373    #[conditional] fn leading_ones(self) -> Self;
2374    /// For each element in the vector, count the number of leading zeros.
2375    #[conditional] fn leading_zeros(self) -> Self;
2376    /// For each element in the vector, count the number of trailing ones.
2377    #[conditional] fn trailing_ones(self) -> Self;
2378    /// For each element in the vector, count the number of trailing zeros.
2379    #[conditional] fn trailing_zeros(self) -> Self;
2380
2381    /// For each lane, how many *earlier* lanes hold the same value:
2382    /// `out[i] == |{ j < i : self[j] == self[i] }|`.
2383    ///
2384    /// Equivalent to AVX-512CD's `conflict(self).count_ones()`. Two things fall
2385    /// out of it:
2386    ///
2387    /// - `count_conflicts().cmp_eq(Self::ZERO)` is the **first-occurrence** mask.
2388    /// - The count is the round number for a conflicting read-modify-write. A
2389    ///   lane of rank `r` is safe to process in round `r`, since every earlier
2390    ///   duplicate has a strictly smaller rank and goes first. That is what
2391    ///   makes a vectorized histogram / SAH-bin increment correct where a plain
2392    ///   scatter would silently drop duplicate writes.
2393    ///
2394    /// Backed by [`IntegerRegister::count_conflicts`](crate::register::IntegerRegister::count_conflicts),
2395    /// so a backend with hardware conflict detection overrides it in one place.
2396    fn count_conflicts(self) -> Self;
2397}
2398
2399/// The operations that need both a sign and integer lanes: arithmetic
2400/// (sign-filling) right shifts, the overflow-free averages, and the rounded
2401/// high-half multiply.
2402///
2403/// The meeting point of [`SignedVector`] and [`IntegerVector`], implemented only
2404/// by vectors of signed integer elements (`Vector<i32>`, `i16xN`, ...).
2405#[rustfmt::skip] #[thermite_macros::vector_trait]
2406#[diagnostic::on_unimplemented(
2407    message = "`{Self}` is not a signed integer SIMD vector",
2408    label = "not a signed integer vector",
2409    note = "`SignedIntegerVector` is the meeting point of `SignedVector` and `IntegerVector`: it is implemented only by vectors of signed integer elements (`Vector<i32>`, `i16xN`, ...). Unsigned integer and float vectors do not qualify."
2410)]
2411pub trait SignedIntegerVector: SignedVector + IntegerVector<Element: crate::element::SignedIntegerElement> {
2412    /// For each lane in the vector, right shift in sign bits by the immediate value.
2413    #[conditional] fn srai<const I: i32>(self) -> Self;
2414    /// For each lane in the vector, right shift in sign bits by the given value.
2415    #[conditional] fn sra(self, count: u32) -> Self;
2416    /// For each lane in the vector, right shift in sign bits by the corresponding lane in the shifts vector.
2417    #[conditional] fn srav(self, counts: Self::Unsigned) -> Self;
2418
2419    /// Floor average: `(a + b) >> 1` rounded toward -∞, computed without overflow.
2420    #[conditional] fn avg_floor(self, other: Self) -> Self;
2421    /// Ceiling average: `(a + b + 1) >> 1` rounded toward +∞, computed without overflow.
2422    #[conditional] fn avg_ceil(self, other: Self) -> Self;
2423
2424    /// Rounded high-half signed multiply: the fixed-point `Q(W-1)` product
2425    /// `(self * other + 2^(W-2)) >> (W-1)`, where `W` is the element bit width.
2426    ///
2427    /// For `i16` this is the Q15 rounded multiply (x86 `PMULHRSW`), the
2428    /// fixed-point DSP primitive for gain/volume, fades, and window functions.
2429    /// Unlike [`mulhi`](IntegerVector::mulhi) it rounds to nearest instead of
2430    /// truncating, avoiding a DC bias.
2431    #[conditional] fn mulhrs(self, other: Self) -> Self;
2432}
2433
2434/// The operations that read better on unsigned lanes: the power-of-two and
2435/// inclusive-range predicates, and the unsigned averages.
2436///
2437/// Implemented only by vectors of unsigned integer elements (`Vector<u32>`,
2438/// `u8xN`, ...). Several of these exist here specifically because the unsigned
2439/// form is cheaper: [`in_range`](Self::in_range) is one wrapping subtract and
2440/// one compare, against the two compares an explicit `lo <= x && x <= hi` costs.
2441#[rustfmt::skip] #[thermite_macros::vector_trait]
2442#[diagnostic::on_unimplemented(
2443    message = "`{Self}` is not an unsigned integer SIMD vector",
2444    label = "not an unsigned integer vector",
2445    note = "`UnsignedIntegerVector` is implemented only by vectors of unsigned integer elements (`Vector<u32>`, `u8xN`, ...). Signed integer and float vectors do not qualify."
2446)]
2447pub trait UnsignedIntegerVector: IntegerVector<Element: crate::element::UnsignedIntegerElement> {
2448    /// Determines if each unsigned integer element in the vector is a
2449    /// power of two, returning a mask indicating whether or not it is.
2450    fn is_power_of_two(self) -> Self::Mask;
2451
2452    /// Per-lane inclusive unsigned range test: a mask of `lo <= self <= hi`,
2453    /// assuming `lo <= hi`.
2454    ///
2455    /// Computed branchlessly as `(self - lo) <= (hi - lo)` with wrapping
2456    /// subtraction: a single unsigned compare instead of the two an explicit
2457    /// `self >= lo & self <= hi` would need. The workhorse of byte
2458    /// classification - testing digit/alpha/whitespace ranges.
2459    fn in_range(self, lo: Self, hi: Self) -> Self::Mask;
2460
2461    /// Returns the next power of two minus one for each unsigned integer
2462    /// element in the vector.
2463    #[conditional] fn next_power_of_two_m1(self) -> Self;
2464    /// Computes log2(x) + 1 for each unsigned integer element in the vector.
2465    #[conditional] fn ilog2p1(self) -> Self;
2466
2467    /// Compute the parity of each unsigned integer lane in the vector.
2468    #[conditional] fn parity(self) -> Self;
2469
2470    /// Ceiling average: `(a + b + 1) >> 1`, computed without overflow.
2471    ///
2472    /// Matches x86 `PAVGB`/`PAVGW` and ARM `vrhadd` semantics.
2473    #[conditional] fn avg(self, other: Self) -> Self;
2474
2475    /// Per-lane unsigned absolute difference `|self - other|`, without overflow.
2476    ///
2477    /// Computed branchlessly as `(self -| other) | (other -| self)` with
2478    /// saturating subtraction. The per-lane building block of sum-of-absolute-
2479    /// differences (block matching, motion estimation).
2480    #[conditional] fn abs_diff(self, other: Self) -> Self;
2481
2482    /// Per-lane `N`-dimensional Morton code (Z-order curve index): interleave the
2483    /// low `floor(W / N)` bits of each of the `N` coordinate vectors into one,
2484    /// placing bit `i` of `values[d]` at output position `i * N + d`. `N = 2` is
2485    /// the classic 2D code, `N = 3` the 3D (voxel/octree) code.
2486    ///
2487    /// The workhorse for spatial sorting (BVH/octree builds, grid binning,
2488    /// nearest-neighbour broad-phase): compute a whole vector of codes at once,
2489    /// then sort. [`reverse_morton`](Self::reverse_morton) inverts it.
2490    fn morton<const N: usize>(values: [Self; N]) -> Self;
2491
2492    /// Inverse of [`morton`](Self::morton): de-interleave a Morton code back into
2493    /// its `N` coordinate vectors, where `out[d]` gathers output bits
2494    /// `d, d + N, d + 2N, ...` into the low `floor(W / N)` bits.
2495    fn reverse_morton<const N: usize>(self) -> [Self; N];
2496}
2497
2498/// Escape hatch tying a [`Vector`] to its specific underlying
2499/// [`Register`](crate::register::Register) type.
2500///
2501/// Provides round-trip conversion between the user-facing [`Vector`] and the
2502/// raw register storage. Most generic code should bound on
2503/// [`GenericVector`] (or a more specific vector trait) and never need this;
2504/// it exists so that code which deliberately specializes on a particular
2505/// backend can drop down to the register layer without losing the trait
2506/// hierarchy on the way back up.
2507pub trait VectorWithRegister<R: crate::register::Register>: GenericVector {
2508    /// Consume the vector and yield its raw register storage.
2509    fn into_register(self) -> crate::register::Storage<R>;
2510
2511    /// Wrap a raw register storage value back into a `Vector`.
2512    fn from_register(reg: crate::register::Storage<R>) -> Self;
2513
2514    /// Borrow the vector's elements as a slice.
2515    ///
2516    /// The lane count travels as the slice length (always
2517    /// [`lanes()`](GenericVector::lanes)) rather than in the type, so this is the
2518    /// preferred read accessor over array-typed borrows.
2519    fn as_slice(&self) -> &[Self::Element];
2520
2521    /// Mutably borrow the vector's elements as a slice.
2522    ///
2523    /// See [`as_slice`](Self::as_slice).
2524    fn as_mut_slice(&mut self) -> &mut [Self::Element];
2525}
2526
2527/// Float vector types which have an associated hardware register type.
2528pub trait FloatVectorWithRegister:
2529    FloatVectorWithBits<Mask = crate::Mask<Self::Register>> + VectorWithRegister<Self::Register>
2530{
2531    /// The backing hardware register this vector is a thin wrapper over.
2532    type Register: crate::register::FloatRegister<Element = Self::Element, Lanes = Self::Lanes>;
2533}
2534
2535/// SignedBits integer vector types which have an associated hardware register type.
2536pub trait SignedIntegerVectorWithRegister:
2537    SignedIntegerVector<Mask = crate::Mask<Self::Register>> + VectorWithRegister<Self::Register>
2538{
2539    /// The backing hardware register this vector is a thin wrapper over.
2540    type Register: crate::register::SignedIntegerRegister<Element = Self::Element, Lanes = Self::Lanes>;
2541}
2542
2543/// Unsigned integer vector types which have an associated hardware register type.
2544pub trait UnsignedIntegerVectorWithRegister:
2545    UnsignedIntegerVector<Mask = crate::Mask<Self::Register>> + VectorWithRegister<Self::Register>
2546{
2547    /// The backing hardware register this vector is a thin wrapper over.
2548    type Register: crate::register::UnsignedIntegerRegister<Element = Self::Element, Lanes = Self::Lanes>;
2549}
2550
2551/// Floating-point vectors: the bound most user code should be written against.
2552///
2553/// Carries the float arithmetic, rounding, the FMA family, the predicates
2554/// (`is_finite`, `is_nan`, ...) and the [`FloatConsts`] values, on top of
2555/// everything [`SignedVector`] provides. The policy math library
2556/// ([`CoreMath`](crate::math::CoreMath),
2557/// [`TranscendentalMath`](crate::math::TranscendentalMath) and the rest) attaches
2558/// to this bound, so `V: FloatVector + TranscendentalMath` is the usual signature
2559/// for a numeric kernel.
2560///
2561/// Implemented by the 1-lane `Vector<f32>` / `Vector<f64>`, the native-width
2562/// `f32xN` / `f64xN`, and the composite float types (`Dual`, `Complex`,
2563/// `Compensated`), which is what lets one generic function run as plain SIMD, as
2564/// autodiff, or in double-double precision without being edited.
2565///
2566/// Bare `f32` and `f64` do **not** implement it. Wrap the scalar first with
2567/// `Vector::<f32>::splat(x)`, or use [`ScalarMath`](crate::math::ScalarMath) for
2568/// one-off scalar math.
2569#[rustfmt::skip] #[thermite_macros::vector_trait]
2570#[diagnostic::on_unimplemented(
2571    message = "`{Self}` is not a floating-point SIMD vector",
2572    label = "not a float vector",
2573    note = "`FloatVector` is implemented by float vectors: the 1-lane `Vector<f32>` / `Vector<f64>`, the native-width `f32xN` / `f64xN`, and composite float types (`Dual`, `Complex`, `Compensated`).",
2574    note = "Bare `f32` / `f64` do NOT implement `FloatVector`. Wrap the scalar first - `Vector::<f32>::splat(x)` or `Vector(x)` - or, for one-off scalar math, use `ScalarMath` (`x.scalar_sqrt()`, `x.scalar_exp()`, ...).",
2575    note = "Integer vectors are not float vectors either; convert with `.to_float()` or a cast before calling float operations."
2576)]
2577pub trait FloatVector: SignedVector<Element: FloatElement>
2578    + FloatConsts
2579    + CastVector<Self::ExtendedPrecision>
2580    + ops::MulAddExtMasked<Self::Mask, Self, Self, Output = Self>
2581    + ops::MulAddAssignExtMasked<Self::Mask, Self, Self>
2582    + ops::AddSubExtMasked<Self::Mask, Output = Self>
2583{
2584    /// The value `0.5` represented in this vector type.
2585    const HALF: Self;
2586    /// The value `-0.0` represented in this vector type.
2587    const NEG_ZERO: Self;
2588    /// The value `infinity` represented in this vector type.
2589    const INFINITY: Self;
2590    /// The value `-infinity` represented in this vector type.
2591    const NEG_INFINITY: Self;
2592    /// The value `NaN` represented in this vector type.
2593    const NAN: Self;
2594    /// Hardware epsilon value in this vector type.
2595    const EPSILON: Self;
2596
2597    /// If available, an extended precision floating point vector type
2598    /// corresponding to this vector type. E.g., for `f32` vectors, this
2599    /// would be an `f64` vector type.
2600    ///
2601    /// If no such type exists, this will be the same as `Self`.
2602    type ExtendedPrecision: FloatVector<Lanes = Self::Lanes> + CastVector<Self>;
2603
2604    /// Check if each element in the vector is infinite, returning a mask.
2605    fn is_infinite(self) -> Self::Mask;
2606
2607    /// Check if each element in the vector is finite, returning a mask.
2608    fn is_finite(self) -> Self::Mask;
2609
2610    /// Check if each element in the vector is NaN, returning a mask.
2611    fn is_nan(self) -> Self::Mask;
2612
2613    /// Check if each element in the vector is zero or subnormal, returning a mask.
2614    fn is_zero_or_subnormal(self) -> Self::Mask;
2615
2616    /// Check if each element in the vector is normal, returning a mask.
2617    fn is_normal(self) -> Self::Mask;
2618
2619    /// Check if each element in the vector is subnormal, returning a mask.
2620    fn is_subnormal(self) -> Self::Mask;
2621
2622    /// `true` if the backend has a hardware approximate-reciprocal
2623    /// instruction (e.g. `rcpps` on x86). When `false`, [`rcp`](Self::rcp)
2624    /// falls back to a full IEEE division and provides no speed advantage
2625    /// over `Self::ONE / self`.
2626    const HAS_APPROX_RCP: bool;
2627
2628    /// `true` if the backend has a hardware approximate-reciprocal-square-root
2629    /// instruction (e.g. `rsqrtps` on x86). When `false`, [`rsqrt`](Self::rsqrt)
2630    /// falls back to `Self::ONE / self.sqrt()`.
2631    const HAS_APPROX_RSQRT: bool;
2632
2633    /// Lane-wise IEEE 754 square root.
2634    ///
2635    /// Negative inputs (other than `-0.0`) produce NaN. `sqrt(-0.0)` is `-0.0`.
2636    #[conditional] fn sqrt(self) -> Self;
2637
2638    /// Lane-wise approximate reciprocal square root.
2639    ///
2640    /// Accuracy is hardware-dependent (typically 12 bits on x86 `rsqrtps`,
2641    /// closer to full precision on newer ISAs). For full-precision results
2642    /// or backends without hardware support, see [`HAS_APPROX_RSQRT`](Self::HAS_APPROX_RSQRT).
2643    #[conditional] fn rsqrt(self) -> Self;
2644
2645    /// Lane-wise approximate reciprocal: `1 / self`.
2646    ///
2647    /// Accuracy is hardware-dependent (typically 12 bits on x86 `rcpps`).
2648    /// For full-precision results or backends without hardware support,
2649    /// see [`HAS_APPROX_RCP`](Self::HAS_APPROX_RCP), or use `Self::ONE / self`.
2650    #[conditional] fn rcp(self) -> Self;
2651
2652    /// Lane-wise floor: largest integer less than or equal to each element.
2653    ///
2654    /// Result type stays the same; the value is the integer rounded toward
2655    /// negative infinity, kept in the float representation.
2656    #[conditional] fn floor(self) -> Self;
2657
2658    /// Lane-wise ceiling: smallest integer greater than or equal to each
2659    /// element, kept in the float representation.
2660    #[conditional] fn ceil(self) -> Self;
2661
2662    /// Lane-wise round-to-nearest.
2663    ///
2664    /// Halfway cases follow the current rounding mode of the hardware. On
2665    /// x86 this is round-half-to-even (banker's rounding), which differs
2666    /// from the scalar `f32::round` / `f64::round` half-away-from-zero
2667    /// convention. If you need a specific tie-breaking rule, do it explicitly.
2668    #[conditional] fn round(self) -> Self;
2669
2670    /// Lane-wise truncation toward zero (drops the fractional part), kept
2671    /// in the float representation.
2672    #[conditional] fn trunc(self) -> Self;
2673
2674    /// Lane-wise fractional part: `self - self.trunc()`.
2675    ///
2676    /// Result has the same sign as the input. For very large magnitudes the
2677    /// fractional part is exactly zero because the float has no fractional bits.
2678    #[conditional] fn fract(self) -> Self;
2679
2680    /// Effectively `self * sign.signum()`, multiplying the sign bits.
2681    #[conditional] fn mul_sign(self, sign: Self) -> Self;
2682
2683    /// Returns zero with the sign of `self`, i.e.: only the sign bit is set.
2684    #[conditional] fn signed_zero(self) -> Self;
2685
2686    /// Returns the next representable value greater than the current value, towards positive infinity.
2687    #[conditional] fn next_up(self) -> Self;
2688
2689    /// Returns the next representable value less than the current value, towards negative infinity.
2690    #[conditional] fn next_down(self) -> Self;
2691
2692    /// Linearly interpolates between `a` and `b` by `self`, where `self` is typically in the range `[0, 1]`.
2693    ///
2694    /// Follows the formula: `a * (1 - self) + b * self`, but the underlying implementation
2695    /// may optimize into certain other formulations.
2696    fn mix(self, a: Self, b: Self) -> Self;
2697
2698    /// Computes `$1 - x^2$` accurately, avoiding the cancellation a naive `1 - self * self`
2699    /// suffers as `self` approaches `±1` (where the result is small but `self * self` is near 1).
2700    ///
2701    /// With hardware FMA this is `nmul_add(self, self, 1)`: the exact product `$x^2$` is formed
2702    /// and subtracted from one with a single rounding. Without FMA it falls back to the factored
2703    /// `$(1 - x)(1 + x)$`, also cancellation-free (`1 - self` is exact for `self` near 1 by
2704    /// Sterbenz's lemma). Both keep full relative accuracy in the small result.
2705    #[inline(always)]
2706    fn one_minus_sq(self) -> Self {
2707        if const { Self::HAS_TRUE_FMA } {
2708            // FMA: 1 - self*self formed from the exact product with a single rounding.
2709            self.nmul_add(self, Self::ONE)
2710        } else {
2711            // No FMA: factored difference of squares, cancellation-free near |self| = 1.
2712            (Self::ONE - self) * (Self::ONE + self)
2713        }
2714    }
2715
2716    /// Inhibit further LLVM auto-vectorization of code surrounding this call.
2717    ///
2718    /// LLVM sometimes tries to "vectorize the vectors" -- repacking
2719    /// already-SIMD code into a wider form that ends up slower. Inserting
2720    /// this call inside a hot loop blocks that pass at the use site. The
2721    /// call itself emits no instructions; only the optimizer barrier remains.
2722    ///
2723    /// # Safety
2724    ///
2725    /// Memory-safe to call, but the side effect on code generation is
2726    /// significant. Only reach for this when you have measured a regression
2727    /// caused by over-aggressive auto-vectorization.
2728    unsafe fn block_autovectorization(&mut self);
2729
2730    /// Attempt to upcast this FloatVector to a FloatVectorWithBits,
2731    /// using the provided kernel. If not possible, returns None.
2732    fn with_bits<const N: usize, K: AsFloatVectorWithBitsKernel<Self, N>>(
2733        _values: [Self; N],
2734        _kernel: K,
2735    ) -> Option<<K as AsFloatVectorWithBitsKernel<Self, N>>::Output> {
2736        None // Default implementation returns None
2737    }
2738}
2739
2740/// Inclusive scan ladder at the **vector** layer, for composite vector types.
2741///
2742/// The register-layer ladder in
2743/// [`polyfills::scan`](crate::backend::generic::polyfills::scan) is written in
2744/// `Register` ops and so cannot be reused by `Dual`/`Compensated`/`Complex`, whose
2745/// scans have to run on their own `Self` operations (a dual carries the winning
2746/// lane's derivative; a compensated sum has to renormalise its error term). This is
2747/// the same ladder spelled in [`GenericVector`] methods, exported so those crates
2748/// share one copy.
2749///
2750/// Invoke inside an `impl` block for the composite -- it resolves `Self`:
2751///
2752/// ```ignore
2753/// fn prefix_min(self) -> Self {
2754///     thermite::scan_ladder!(forward, self, self.broadcast::<0>(), Self::min)
2755/// }
2756/// fn reverse_prefix_sum(self) -> Self {
2757///     thermite::scan_ladder!(reverse, self, Self::ZERO, core::ops::Add::add)
2758/// }
2759/// ```
2760///
2761/// `$op` must be associative (a doubling ladder reassociates freely), and `$fill`
2762/// must leave the already-final lanes alone: `ZERO` for a sum, and a broadcast of
2763/// the *edge* lane for `min`/`max` -- lane 0 forward, lane `LANES - 1` reverse.
2764/// `MIN`/`MAX` are finite bounds and would clamp an infinite lane, which is the same
2765/// trap the register ladder documents.
2766///
2767/// `align`'s offset is a const-generic argument and must be a literal. The reverse
2768/// direction is fine (the shift *is* the offset), but the forward direction needs
2769/// `LANES - s`, hence the match on the compile-time lane count with a per-width
2770/// offset list -- exactly one arm survives monomorphization. Widths outside
2771/// power-of-two `<= 64` have no arm and fall back to reversing, running the reverse
2772/// ladder, and reversing back, which needs only literal shifts and is correct at any
2773/// width.
2774///
2775/// Every stage is an `align`, so on a vector whose
2776/// [`HAS_NATIVE_ALIGN`](GenericVector::HAS_NATIVE_ALIGN) is false each one expands to
2777/// a shuffle-and-blend and the ladder gets correspondingly more expensive. It is
2778/// still `ceil(log2(LANES))` stages against a per-lane walk's `LANES` extract/insert
2779/// pairs, which is why this does not switch lowering the way the register-layer
2780/// ladder does -- there the fallback walks a slice in place and is genuinely cheaper.
2781/// Gate on the const at the call site if a specific composite says otherwise.
2782#[rustfmt::skip]
2783#[doc(hidden)]
2784#[macro_export]
2785macro_rules! scan_ladder {
2786    (reverse, $v:expr, $fill:expr, $op:path) => {{
2787        let mut v = $v;
2788        let f = $fill;
2789        let () = {
2790            if const { Self::LANES >  1 } { v = $op(v, v.align::<1>(f)); }
2791            if const { Self::LANES >  2 } { v = $op(v, v.align::<2>(f)); }
2792            if const { Self::LANES >  4 } { v = $op(v, v.align::<4>(f)); }
2793            if const { Self::LANES >  8 } { v = $op(v, v.align::<8>(f)); }
2794            if const { Self::LANES > 16 } { v = $op(v, v.align::<16>(f)); }
2795            if const { Self::LANES > 32 } { v = $op(v, v.align::<32>(f)); }
2796        };
2797        v
2798    }};
2799
2800    (forward, $v:expr, $fill:expr, $op:path) => {{
2801        let mut v = $v;
2802        let f = $fill;
2803
2804        if const { Self::LANES.is_power_of_two() && Self::LANES <= 64 } {
2805            // `a.align::<OFFSET>(b)[i] == concat(a, b)[OFFSET + i]`, so with `a = fill`
2806            // and `b = v` the stage that wants `v[i - s]` is `OFFSET == LANES - s`.
2807            let () = match const { Self::LANES } {
2808                0 | 1 => {}
2809                2  => { v = $op(v, f.align::<1>(v)); }
2810                4  => { v = $op(v, f.align::<3>(v));
2811                        v = $op(v, f.align::<2>(v)); }
2812                8  => { v = $op(v, f.align::<7>(v));
2813                        v = $op(v, f.align::<6>(v));
2814                        v = $op(v, f.align::<4>(v)); }
2815                16 => { v = $op(v, f.align::<15>(v));
2816                        v = $op(v, f.align::<14>(v));
2817                        v = $op(v, f.align::<12>(v));
2818                        v = $op(v, f.align::<8>(v)); }
2819                32 => { v = $op(v, f.align::<31>(v));
2820                        v = $op(v, f.align::<30>(v));
2821                        v = $op(v, f.align::<28>(v));
2822                        v = $op(v, f.align::<24>(v));
2823                        v = $op(v, f.align::<16>(v)); }
2824                64 => { v = $op(v, f.align::<63>(v));
2825                        v = $op(v, f.align::<62>(v));
2826                        v = $op(v, f.align::<60>(v));
2827                        v = $op(v, f.align::<56>(v));
2828                        v = $op(v, f.align::<48>(v));
2829                        v = $op(v, f.align::<32>(v)); }
2830                // unreachable: guarded by the `if const` above. Panicking is the right
2831                // failure mode if a width ever slips past that guard.
2832                _ => unreachable!(),
2833            };
2834            v
2835        } else {
2836            // `fill` is the lane-0 broadcast either way: reversing makes it the last
2837            // lane, which is exactly what the reverse ladder wants.
2838            $crate::scan_ladder!(reverse, v.reverse(), f, $op).reverse()
2839        }
2840    }};
2841}
2842
2843/// Run a closure-like block with a generic [`FloatVector`] temporarily upcast
2844/// to a [`FloatVectorWithBits`], when the backend supports it.
2845///
2846/// Given an array of `FloatVector` values and a body parameterized over a
2847/// `FloatVectorWithBits` type, this expands to a call to
2848/// [`FloatVector::with_bits`] with an anonymous kernel implementing
2849/// [`AsFloatVectorWithBitsKernel`]. The body only runs when bit access is
2850/// available for the concrete backend; otherwise the whole expression evaluates
2851/// to `None` (the return type is therefore `Option<_>`).
2852///
2853/// This is the ergonomic front-end to the [`AsFloatVectorWithBitsKernel`]
2854/// pattern; reach for it inside generic code bounded only on `FloatVector` that
2855/// wants an optional fast path requiring bit-level access.
2856#[macro_export]
2857macro_rules! with_bits {
2858    // (($first_value:expr $(, $value:expr)+): $ty:ty as fn($first_decl:ident: $first_alias:ident $(,$decl:ident: $alias:ident)* ) -> $ret:ty $(where $($c:ty: $constraint:ident),*)? { $($body:tt)* }) => {{
2859    //     $crate::with_bits!(($first_value): $ty as fn($first_decl: $first_alias) -> impl $ret $(where $($c: $constraint),*)? {
2860    //         $crate::with_bits!(($($value),+): $ty as fn($($decl: $alias),*) -> $ret $(where $($c: $constraint),*)? {
2861    //             $($body)*
2862    //         })
2863    //     })
2864    // }};
2865
2866    ([$($values:expr),+]: [$ty:ty; $len:literal] as fn($decl:ident: [$alias:ident; _]) -> $ret:ty $(where $($c:ty: $constraint:ident),*)? { $($body:tt)* }) => {{
2867        struct AnonymousAsFloatVectorWithBitsKernel<V>(core::marker::PhantomData<V>);
2868
2869        impl<V: FloatVector> $crate::vector::AsFloatVectorWithBitsKernel<V, $len> for AnonymousAsFloatVectorWithBitsKernel<V>
2870            $(where $($c: $constraint),*)?
2871        {
2872            type Output = $ret;
2873
2874            fn with_bits<
2875                $alias: FloatVectorWithBits<
2876                        Element = V::Element,
2877                        Lanes = V::Lanes,
2878                        Mask = V::Mask,
2879                        Signed = V::Signed,
2880                        Unsigned = V::Unsigned,
2881                        ExtendedPrecision = V::ExtendedPrecision,
2882                    > + CastVector<V>,
2883            >(
2884                self,
2885                $decl: [$alias; $len],
2886            ) -> Self::Output {
2887                $($body)*
2888            }
2889        }
2890
2891        <V as FloatVector>::with_bits(
2892            [$($values),+],
2893            AnonymousAsFloatVectorWithBitsKernel::<V>(core::marker::PhantomData),
2894        )
2895    }};
2896}
2897
2898/// Some algorithms may benefit from being able to access the bitwise
2899/// representation of floating point vectors. However, not all vectors
2900/// support this functionality, and those that do may be passed as generic
2901/// FloatVector. Therefore, this is a way of upcasting a FloatVector
2902/// to a FloatVectorWithBits, if possible. If not possible, returns None.
2903pub trait AsFloatVectorWithBitsKernel<O: FloatVector, const N: usize> {
2904    /// Whatever the kernel body returns, threaded back out through the upcast.
2905    type Output;
2906
2907    /// Runs the kernel with `v` re-typed as a [`FloatVectorWithBits`].
2908    ///
2909    /// The bound is written on the method rather than the trait so the caller
2910    /// stays generic over plain [`FloatVector`]. The bit-level type only exists
2911    /// inside this call.
2912    fn with_bits<
2913        V: FloatVectorWithBits<
2914                Element = O::Element,
2915                Lanes = O::Lanes,
2916                Mask = O::Mask,
2917                Signed = O::Signed,
2918                Unsigned = O::Unsigned,
2919                ExtendedPrecision = O::ExtendedPrecision,
2920            > + CastVector<O>,
2921    >(
2922        self,
2923        v: [V; N],
2924    ) -> Self::Output;
2925}
2926
2927/// A [`FloatVector`] that additionally exposes its raw bit representation as
2928/// companion integer vectors, enabling bit-level float algorithms.
2929///
2930/// On top of [`FloatVector`] this provides:
2931/// - the [`Bits`](Self::Bits) (unsigned) and [`SignedBits`](Self::SignedBits)
2932///   integer vector types matching this float's bit width and lane count, with
2933///   full [`FullyInteroperable`] cast/bitcast interop between all three views;
2934/// - hardware-accelerated `native_*` transcendentals gated by
2935///   [`NATIVE_CAP`](Self::NATIVE_CAP);
2936/// - bit-level helpers like [`total_order`](Self::total_order) /
2937///   [`linear_order`](Self::linear_order) for sorting and ULP math.
2938///
2939/// Not every float vector implements this (it requires the element to be a
2940/// [`FloatElementWithBits`]); generic code that only sometimes needs bit access
2941/// can attempt to obtain it via [`FloatVector::with_bits`].
2942///
2943/// The methods on this trait do **not** have masked (`_c`/`_m`/`_z`) variants.
2944#[diagnostic::on_unimplemented(
2945    message = "`{Self}` does not expose float bit-manipulation operations",
2946    label = "no `ldexp` / `frexp` or raw bit access",
2947    note = "`FloatVectorWithBits` is implemented by concrete float vectors (`Vector<f32>`, `f32xN`, ...). Composite float types such as `Dual` / `Compensated` may not expose raw bit access, so bound on `FloatVector` instead unless you specifically need bit-level ops."
2948)]
2949pub trait FloatVectorWithBits:
2950    BitwiseVector
2951    + FloatVector<Element: FloatElementWithBits, Signed: CastVector<Self::SignedBits>, Unsigned: CastVector<Self::Bits>>
2952    + GenericVector<
2953        Signed: GenericVector<Mask: CastMask<<Self::SignedBits as GenericVector>::Mask>>,
2954        Unsigned: GenericVector<Mask: CastMask<<Self::Unsigned as GenericVector>::Mask>>,
2955    > + FullyInteroperable<Self::Bits, Self::SignedBits>
2956{
2957    /// This vector's bit pattern viewed as *signed* integer lanes of the same
2958    /// width, for exponent arithmetic and the sign-aware bit tricks.
2959    type SignedBits: SignedIntegerVector<
2960            Mask: CastMask<<Self::Signed as GenericVector>::Mask>,
2961            Lanes = Self::Lanes,
2962            Divider = Divider<<Self::Element as FloatElementWithBits>::SignedBits>,
2963            BranchfreeDivider = BranchfreeDivider<<Self::Element as FloatElementWithBits>::SignedBits>,
2964            Element = <Self::Element as FloatElementWithBits>::SignedBits,
2965        > + FullyInteroperable<Self, Self::Bits>
2966        + CastVector<Self::Signed>;
2967
2968    /// This vector's bit pattern viewed as *unsigned* integer lanes of the same
2969    /// width, which is what masking and shifting the raw bits wants.
2970    type Bits: UnsignedIntegerVector<
2971            Mask: CastMask<<Self::Unsigned as GenericVector>::Mask>,
2972            Lanes = Self::Lanes,
2973            Divider = Divider<<Self::Element as FloatElementWithBits>::Bits>,
2974            BranchfreeDivider = BranchfreeDivider<<Self::Element as FloatElementWithBits>::Bits>,
2975            Element = <Self::Element as FloatElementWithBits>::Bits,
2976        > + FullyInteroperable<Self, Self::SignedBits>
2977        + CastVector<Self::Unsigned>;
2978
2979    /// Bit-flag set describing which `native_*` methods on this trait have a
2980    /// real hardware implementation on the current backend.
2981    ///
2982    /// Test with `NATIVE_CAP.has(NativeCapability::SIN)` etc. before calling
2983    /// the corresponding `native_*` method directly; otherwise the default
2984    /// implementation will panic.
2985    const NATIVE_CAP: NativeCapability;
2986
2987    /// Hardware-accelerated `ldexp`: `self * 2^exp`, lane-wise.
2988    ///
2989    /// # Safety
2990    /// Only callable when [`NATIVE_CAP`](Self::NATIVE_CAP) advertises `LDEXP`.
2991    /// Calling on a backend without hardware support is undefined behavior
2992    /// (the default impl panics via `unreachable!` at the register layer).
2993    unsafe fn native_ldexp(self, exp: Self::SignedBits) -> Self;
2994
2995    /// Hardware-accelerated `frexp`: split each lane into a normalized
2996    /// mantissa in `[0.5, 1.0)` and an integer exponent.
2997    ///
2998    /// # Safety
2999    /// Only callable when [`NATIVE_CAP`](Self::NATIVE_CAP) advertises `FREXP`.
3000    unsafe fn native_frexp(self) -> (Self, Self::SignedBits);
3001
3002    /// Hardware-accelerated combined sine and cosine, lane-wise.
3003    ///
3004    /// # Safety
3005    /// Only callable when [`NATIVE_CAP`](Self::NATIVE_CAP) advertises `SIN_COS`.
3006    unsafe fn native_sin_cos<P: Policy>(self) -> (Self, Self);
3007
3008    /// Hardware-accelerated sine, lane-wise.
3009    ///
3010    /// # Safety
3011    /// Only callable when [`NATIVE_CAP`](Self::NATIVE_CAP) advertises `SIN`.
3012    unsafe fn native_sin<P: Policy>(self) -> Self;
3013
3014    /// Hardware-accelerated cosine, lane-wise.
3015    ///
3016    /// # Safety
3017    /// Only callable when [`NATIVE_CAP`](Self::NATIVE_CAP) advertises `COS`.
3018    unsafe fn native_cos<P: Policy>(self) -> Self;
3019
3020    /// Hardware-accelerated tangent, lane-wise.
3021    ///
3022    /// # Safety
3023    /// Only callable when [`NATIVE_CAP`](Self::NATIVE_CAP) advertises `TAN`.
3024    unsafe fn native_tan<P: Policy>(self) -> Self;
3025
3026    /// Hardware-accelerated `2^self`, lane-wise.
3027    ///
3028    /// # Safety
3029    /// Only callable when [`NATIVE_CAP`](Self::NATIVE_CAP) advertises `EXP2`.
3030    unsafe fn native_exp2<P: Policy>(self) -> Self;
3031
3032    /// Hardware-accelerated `log2(self)`, lane-wise.
3033    ///
3034    /// # Safety
3035    /// Only callable when [`NATIVE_CAP`](Self::NATIVE_CAP) advertises `LOG2`.
3036    unsafe fn native_log2<P: Policy>(self) -> Self;
3037
3038    /// Hardware-accelerated `e^self`, lane-wise.
3039    ///
3040    /// # Safety
3041    /// Only callable when [`NATIVE_CAP`](Self::NATIVE_CAP) advertises `EXP`.
3042    unsafe fn native_exp<P: Policy>(self) -> Self;
3043
3044    /// Hardware-accelerated natural logarithm, lane-wise.
3045    ///
3046    /// # Safety
3047    /// Only callable when [`NATIVE_CAP`](Self::NATIVE_CAP) advertises `LN`.
3048    unsafe fn native_ln<P: Policy>(self) -> Self;
3049
3050    /// Hardware-accelerated `self^exp`, lane-wise.
3051    ///
3052    /// # Safety
3053    /// Only callable when [`NATIVE_CAP`](Self::NATIVE_CAP) advertises `POWF`.
3054    unsafe fn native_powf<P: Policy>(self, exp: Self) -> Self;
3055
3056    /// Return a signed integer vector that is capable of encapsulating
3057    /// the "total order" of the floating point values in this vector, /// such that when compared as integers, the ordering is the same
3058    /// as the floating point ordering, including NaNs, in the following order:
3059    ///
3060    /// - negative quiet NaN
3061    /// - negative signaling NaN
3062    /// - negative infinity
3063    /// - negative numbers
3064    /// - negative subnormal numbers
3065    /// - negative zero
3066    /// - positive zero
3067    /// - positive subnormal numbers
3068    /// - positive numbers
3069    /// - positive infinity
3070    /// - positive signaling NaN
3071    /// - positive quiet NaN.
3072    ///
3073    /// This is useful for sorting floating point numbers in a way that
3074    /// is consistent and well-defined. However, it may differ from
3075    /// the default floating point comparison behavior of the platform.
3076    ///
3077    /// # Example
3078    /// ```rust
3079    /// # use thermite::backend::scalar::prelude::*;
3080    /// let x = f32x4::NAN;
3081    /// let y = f32x4::ONE;
3082    /// let total_lt = x.total_order().cmp_lt(y.total_order());
3083    /// assert!(total_lt.none()); // NaN is not less than 1.0 in total order
3084    /// ```
3085    fn total_order(self) -> Self::SignedBits;
3086
3087    /// Similar to [`total_order`](FloatVectorWithBits::total_order), but positive zero and negative zero are
3088    /// the same value. This can be used for calculating ULP differences by simply subtracting one from another.
3089    fn linear_order(self) -> Self::SignedBits;
3090}
3091
3092/// Convenience accessors `x()` / `y()` automatically available on any
3093/// 2-lane [`GenericVector`].
3094///
3095/// Each method is just shorthand for [`extract`](GenericVector::extract) at
3096/// the corresponding compile-time index.
3097#[rustfmt::skip]
3098pub trait GenericVector2: GenericVector {
3099    /// Returns the value of lane 0.
3100    #[inline(always)] fn x(&self) -> Self::Element { self.extract::<0>() }
3101    /// Returns the value of lane 1.
3102    #[inline(always)] fn y(&self) -> Self::Element { self.extract::<1>() }
3103}
3104
3105/// Convenience accessors `x()` / `y()` / `z()` automatically available on any
3106/// 3-lane [`GenericVector`].
3107///
3108/// Each method is just shorthand for [`extract`](GenericVector::extract) at
3109/// the corresponding compile-time index.
3110#[rustfmt::skip]
3111pub trait GenericVector3: GenericVector {
3112    /// Returns the value of lane 0.
3113    #[inline(always)] fn x(&self) -> Self::Element { self.extract::<0>() }
3114    /// Returns the value of lane 1.
3115    #[inline(always)] fn y(&self) -> Self::Element { self.extract::<1>() }
3116    /// Returns the value of lane 2.
3117    #[inline(always)] fn z(&self) -> Self::Element { self.extract::<2>() }
3118}
3119
3120/// Convenience accessors `x()` / `y()` / `z()` / `w()` automatically available
3121/// on any 4-lane [`GenericVector`].
3122///
3123/// Each method is just shorthand for [`extract`](GenericVector::extract) at
3124/// the corresponding compile-time index.
3125#[rustfmt::skip]
3126pub trait GenericVector4: GenericVector {
3127    /// Returns the value of lane 0.
3128    #[inline(always)] fn x(&self) -> Self::Element { self.extract::<0>() }
3129    /// Returns the value of lane 1.
3130    #[inline(always)] fn y(&self) -> Self::Element { self.extract::<1>() }
3131    /// Returns the value of lane 2.
3132    #[inline(always)] fn z(&self) -> Self::Element { self.extract::<2>() }
3133    /// Returns the value of lane 3.
3134    #[inline(always)] fn w(&self) -> Self::Element { self.extract::<3>() }
3135}
3136
3137impl<V: GenericVector<Lanes = typenum::U2>> GenericVector2 for V {}
3138impl<V: GenericVector<Lanes = typenum::U3>> GenericVector3 for V {}
3139impl<V: GenericVector<Lanes = typenum::U4>> GenericVector4 for V {}
3140
3141#[rustfmt::skip]
3142macro_rules! impl_swizzle4 {
3143    (@ x) => { 0 };
3144    (@ y) => { 1 };
3145    (@ z) => { 2 };
3146    (@ w) => { 3 };
3147
3148    (IMPL x x x x) => { #[inline(always)] fn xxxx(self) -> Self { self.broadcast::<0>() } };
3149    (IMPL y y y y) => { #[inline(always)] fn yyyy(self) -> Self { self.broadcast::<1>() } };
3150    (IMPL z z z z) => { #[inline(always)] fn zzzz(self) -> Self { self.broadcast::<2>() } };
3151    (IMPL w w w w) => { #[inline(always)] fn wwww(self) -> Self { self.broadcast::<3>() } };
3152
3153    (IMPL $a:ident $b:ident $c:ident $d:ident) => {paste::paste! {
3154        #[inline(always)]
3155        fn [<$a $b $c $d>](self) -> Self {
3156            struct Indices;
3157
3158            impl crate::swizzle::SwizzleIndices<typenum::U4> for Indices {
3159                const INDICES: GenericArray<u32, typenum::U4> = {
3160                    unsafe { $crate::generic_array::const_transmute::<_, GenericArray<u32, typenum::U4>>([
3161                        impl_swizzle4!(@ $a),
3162                        impl_swizzle4!(@ $b),
3163                        impl_swizzle4!(@ $c),
3164                        impl_swizzle4!(@ $d)
3165                    ]) }
3166                };
3167            }
3168
3169            self.permute_const::<Indices>()
3170        }
3171    }};
3172
3173    (DECL $(#[$meta:meta])* $a:ident $b:ident $c:ident $d:ident) => {paste::paste! {
3174        #[allow(missing_docs)]
3175        $(#[$meta])* fn [<$a $b $c $d>](self) -> Self;
3176    }};
3177
3178    ($( $(#[$meta:meta])* [$a:ident $b:ident $c:ident $d:ident]),*) => {
3179        /// Only available for 4-lane vectors, this allows human-readable swizzle/permutations
3180        /// of the vector.
3181        pub trait Swizzle4: SwizzleVector<Lanes = typenum::U4> { $(impl_swizzle4!(DECL $(#[$meta])* $a $b $c $d);)* }
3182
3183        /// Implements 4-lane swizzling for vectors.
3184        impl<V: SwizzleVector<Lanes = typenum::U4>> Swizzle4 for V {
3185            $(impl_swizzle4!(IMPL $a $b $c $d);)*
3186        }
3187    }
3188}
3189
3190#[rustfmt::skip]
3191macro_rules! impl_swizzle3 {
3192    (IMPL x x x) => { #[inline(always)] fn xxx(self) -> Self { self.broadcast::<0>() } };
3193    (IMPL y y y) => { #[inline(always)] fn yyy(self) -> Self { self.broadcast::<1>() } };
3194    (IMPL z z z) => { #[inline(always)] fn zzz(self) -> Self { self.broadcast::<2>() } };
3195
3196    (IMPL $a:ident $b:ident $c:ident) => {paste::paste! {
3197        #[inline(always)]
3198        fn [<$a $b $c>](self) -> Self {
3199            struct Indices;
3200
3201            impl crate::swizzle::SwizzleIndices<typenum::U3> for Indices {
3202                const INDICES: GenericArray<u32, typenum::U3> = {
3203                    unsafe { $crate::generic_array::const_transmute::<_, GenericArray<u32, typenum::U3>>([
3204                        impl_swizzle4!(@ $a),
3205                        impl_swizzle4!(@ $b),
3206                        impl_swizzle4!(@ $c)
3207                    ]) }
3208                };
3209            }
3210
3211            self.permute_const::<Indices>()
3212        }
3213    }};
3214
3215    (DECL $(#[$meta:meta])* $a:ident $b:ident $c:ident) => {paste::paste! {
3216        #[allow(missing_docs)]
3217        $(#[$meta])* fn [<$a $b $c>](self) -> Self;
3218    }};
3219
3220    ($( $(#[$meta:meta])* [$a:ident $b:ident $c:ident]),*) => {
3221        /// Only available for "3-lane" (ignoring 4th lane) [`LinAlg3Register`](crate::register::LinAlg3Register) vectors,
3222        /// this allows human-readable swizzle/permutations of the vector. Permutations
3223        /// will ignore the 4th lane of the register, leaving it unchanged.
3224        pub trait Swizzle3: SwizzleVector<Lanes = typenum::U3> { $(impl_swizzle3!(DECL $(#[$meta])* $a $b $c);)* }
3225
3226        /// Implements 3-lane swizzling for vectors support 3-lane linear algebra operations.
3227        impl<V: SwizzleVector<Lanes = typenum::U3>> Swizzle3 for V {
3228            $(impl_swizzle3!(IMPL $a $b $c);)*
3229        }
3230    }
3231}
3232
3233impl_swizzle3! {
3234    [x y z], [x x x], [x x y], [x x z], [x y x], [x y y], [x z x], [x z y], [x z z],
3235    [y x x], [y x y], [y x z], [y y x], [y y y], [y y z], [y z x], [y z y], [y z z],
3236    [z x x], [z x y], [z x z], [z y x], [z y y], [z y z], [z z x], [z z y], [z z z]
3237}
3238
3239impl_swizzle4! {
3240    [x y z w], [x x x x], [x x x y], [x x x z], [x x x w], [x x y x], [x x y y], [x x y z],
3241    [x x y w], [x x z x], [x x z y], [x x z z], [x x z w], [x x w x], [x x w y], [x x w z],
3242    [x x w w], [x y x x], [x y x y], [x y x z], [x y x w], [x y y x], [x y y y], [x y y z],
3243    [x y y w], [x y z x], [x y z y], [x y z z], [x y w x], [x y w y], [x y w z], [x y w w],
3244    [x z x x], [x z x y], [x z x z], [x z x w], [x z y x], [x z y y], [x z y z], [x z y w],
3245    [x z z x], [x z z y], [x z z z], [x z z w], [x z w x], [x z w y], [x z w z], [x z w w],
3246    [x w x x], [x w x y], [x w x z], [x w x w], [x w y x], [x w y y], [x w y z], [x w y w],
3247    [x w z x], [x w z y], [x w z z], [x w z w], [x w w x], [x w w y], [x w w z], [x w w w],
3248    [y x x x], [y x x y], [y x x z], [y x x w], [y x y x], [y x y y], [y x y z], [y x y w],
3249    [y x z x], [y x z y], [y x z z], [y x z w], [y x w x], [y x w y], [y x w z], [y x w w],
3250    [y y x x], [y y x y], [y y x z], [y y x w], [y y y x], [y y y y], [y y y z], [y y y w],
3251    [y y z x], [y y z y], [y y z z], [y y z w], [y y w x], [y y w y], [y y w z], [y y w w],
3252    [y z x x], [y z x y], [y z x z], [y z x w], [y z y x], [y z y y], [y z y z], [y z y w],
3253    [y z z x], [y z z y], [y z z z], [y z z w], [y z w x], [y z w y], [y z w z], [y z w w],
3254    [y w x x], [y w x y], [y w x z], [y w x w], [y w y x], [y w y y], [y w y z], [y w y w],
3255    [y w z x], [y w z y], [y w z z], [y w z w], [y w w x], [y w w y], [y w w z], [y w w w],
3256    [z x x x], [z x x y], [z x x z], [z x x w], [z x y x], [z x y y], [z x y z], [z x y w],
3257    [z x z x], [z x z y], [z x z z], [z x z w], [z x w x], [z x w y], [z x w z], [z x w w],
3258    [z y x x], [z y x y], [z y x z], [z y x w], [z y y x], [z y y y], [z y y z], [z y y w],
3259    [z y z x], [z y z y], [z y z z], [z y z w], [z y w x], [z y w y], [z y w z], [z y w w],
3260    [z z x x], [z z x y], [z z x z], [z z x w], [z z y x], [z z y y], [z z y z], [z z y w],
3261    [z z z x], [z z z y], [z z z z], [z z z w], [z z w x], [z z w y], [z z w z], [z z w w],
3262    [z w x x], [z w x y], [z w x z], [z w x w], [z w y x], [z w y y], [z w y z], [z w y w],
3263    [z w z x], [z w z y], [z w z z], [z w z w], [z w w x], [z w w y], [z w w z], [z w w w],
3264    [w x x x], [w x x y], [w x x z], [w x x w], [w x y x], [w x y y], [w x y z], [w x y w],
3265    [w x z x], [w x z y], [w x z z], [w x z w], [w x w x], [w x w y], [w x w z], [w x w w],
3266    [w y x x], [w y x y], [w y x z], [w y x w], [w y y x], [w y y y], [w y y z], [w y y w],
3267    [w y z x], [w y z y], [w y z z], [w y z w], [w y w x], [w y w y], [w y w z], [w y w w],
3268    [w z x x], [w z x y], [w z x z], [w z x w], [w z y x], [w z y y], [w z y z], [w z y w],
3269    [w z z x], [w z z y], [w z z z], [w z z w], [w z w x], [w z w y], [w z w z], [w z w w],
3270    [w w x x], [w w x y], [w w x z], [w w x w], [w w y x], [w w y y], [w w y z], [w w y w],
3271    [w w z x], [w w z y], [w w z z], [w w z w], [w w w x], [w w w y], [w w w z], [w w w w]
3272}
3273
3274/// Vector suitable for 3D linear algebra operations.
3275///
3276/// The length of this vector must be either 3 or 4 lanes.
3277///
3278/// Methods in this are specifically optimized to either ignore the fourth lane (if it exists),
3279/// or to use algorithms that map especially well when there are truly only three "lanes",
3280/// such as on GPUs.
3281pub trait LinAlg3Vector: FloatVector {
3282    /// Scalar Product using only the first three lanes of the register as a 3D vector.
3283    ///
3284    /// This is more efficient than a raw scalar product, as there is no need to
3285    /// zero out the last lane of the register.
3286    fn dot3(self, other: Self) -> Self::Element;
3287
3288    /// Cross Product using only the first three lanes of the register as a 3D vector.
3289    ///
3290    /// This is more efficient than a raw cross product, as there is no need to
3291    /// zero out the last lane of the register.
3292    ///
3293    /// The `DOP` generic parameter indicates whether to use the
3294    /// "Difference of Products" method for computing the cross product,
3295    /// which can be more accurate in some cases, but _requires_
3296    /// hardware fused multiply-add instructions to be efficient.
3297    ///
3298    /// If you want the best performance, set `DOP` to `false`.\
3299    /// If you want the best accuracy or have FMA support, set `DOP` to `true`.
3300    fn cross3<const DOP: bool>(self, other: Self) -> Self;
3301
3302    /// Refraction of incident vector `self` through a surface with normal `n`
3303    /// and relative index of refraction `eta` (`$\eta = \eta_i/\eta_t$`). `self` and `n` are
3304    /// assumed unit length.
3305    ///
3306    /// Total internal reflection (`1 - eta^2*(1 - dot(n,self)^2) < 0`) returns the
3307    /// zero vector; otherwise `eta*self - (eta*dot(n,self) + sqrt(k))*n`
3308    fn refract(self, n: Self, eta: Self::Element) -> Self;
3309
3310    /// Efficiently set the 4th (last) lane of the register to 0.0.
3311    ///
3312    /// Useful for sanitizing 3D Homogeneous vectors.
3313    ///
3314    /// See [`LinAlg3Vector::one4`] for similar functionality for 3D points.
3315    fn zero4(self) -> Self;
3316
3317    /// Efficiently set the 4th (last) lane of the register to 1.0.
3318    ///
3319    /// Useful for sanitizing 3D Homogeneous points.
3320    ///
3321    /// See [`LinAlg3Vector::zero4`] for similar functionality for 3D vectors.
3322    fn one4(self) -> Self;
3323
3324    /// Returns the minimum value in the first three lanes of the register.
3325    fn min_element3(self) -> Self::Element;
3326
3327    /// Returns the maximum value in the first three lanes of the register.
3328    fn max_element3(self) -> Self::Element;
3329
3330    /// Returns the sum of the first three elements of the register.
3331    fn sum_elements3(self) -> Self::Element;
3332
3333    /// Returns the product of the first three elements of the register.
3334    fn prod_elements3(self) -> Self::Element;
3335
3336    /// 3x3 Matrix Transpose.
3337    ///
3338    /// Only the first three lanes of each output column are meaningful; the 4th
3339    /// lane (on 4-lane vectors) is unspecified.
3340    fn mat3_transpose(m: &[Self; 3]) -> [Self; 3];
3341
3342    /// 3x3 Matrix-Vector multiplication, assuming `self` as the vector.
3343    fn mat3_vec3_product<const COLUMN_MAJOR: bool>(self, m: &[Self; 3]) -> Self;
3344
3345    /// 3x3 matrix times `N` 3D vectors (small-`N` batch; see
3346    /// [`mat4_vec4_product_array`](LinAlg4Vector::mat4_vec4_product_array)).
3347    fn mat3_vec3_product_array<const COLUMN_MAJOR: bool, const N: usize>(
3348        m: &[Self; 3],
3349        vectors: &[Self; N],
3350    ) -> [Self; N];
3351
3352    /// 3x3 Matrix-Matrix multiplication.
3353    ///
3354    /// If `COLUMN_MAJOR` is `false`, the matrices are treated as row-major and
3355    /// the multiplication order becomes `rhs * lhs`, mirroring
3356    /// [`mat4_product`](LinAlg4Vector::mat4_product).
3357    fn mat3_product<const COLUMN_MAJOR: bool>(lhs: &[Self; 3], rhs: &[Self; 3]) -> [Self; 3];
3358
3359    /// Determinant of a column-major 3x3 matrix.
3360    fn mat3_det(m: &[Self; 3]) -> Self::Element;
3361
3362    /// In-place 3x3 Matrix inversion; **returns the determinant**.
3363    ///
3364    /// An exactly-zero determinant leaves the matrix untouched; a near-zero
3365    /// (ill-conditioned) determinant gives a finite but unreliable result, so
3366    /// inspect the returned determinant before trusting the matrix.
3367    fn mat3_inverse_inplace(m: &mut [Self; 3]) -> Self::Element;
3368
3369    /// 3x3 Matrix inversion.
3370    ///
3371    /// Returns `Some(inverse)`, or `None` if the matrix is exactly singular.
3372    /// Consider [`mat3_inverse_inplace`](Self::mat3_inverse_inplace) (which hands
3373    /// back the determinant) to avoid the copy and to use a custom tolerance.
3374    #[inline(always)]
3375    fn mat3_inverse(m: &[Self; 3]) -> Option<[Self; 3]> {
3376        let mut mat = *m;
3377        if Self::mat3_inverse_inplace(&mut mat) == Self::Element::ZERO {
3378            None
3379        } else {
3380            Some(mat)
3381        }
3382    }
3383
3384    /// "Normal matrix" for transforming normals under non-uniform scale, from
3385    /// the cofactor cross-products of a column-major 3x3.
3386    ///
3387    /// `DIVIDE = true` gives the true inverse-transpose `$(M^{-1})^{T}$` (non-finite if
3388    /// singular); `DIVIDE = false` gives the un-divided cofactor matrix, which is
3389    /// cheaper, never singular, and points normals the same direction (use it
3390    /// when you re-normalize the result). Cheaper than a full inverse either way.
3391    fn mat3_normal<const DIVIDE: bool>(m: &[Self; 3]) -> [Self; 3];
3392}
3393
3394/// Vector suitable for 4D linear algebra operations.
3395///
3396/// Must have exactly 4 lanes.
3397pub trait LinAlg4Vector: LinAlg3Vector {
3398    /// Scalar Product using all four lanes of the register as a 4D vector.
3399    fn dot4(self, other: Self) -> Self::Element;
3400
3401    /// Quaternion multiplication.
3402    ///
3403    /// Method:
3404    /// ```text
3405    /// T1 = (lhs.w * rhs)
3406    /// T2 = (lhs.x * rhs.wzyx) * {+,-,+,-}
3407    /// T3 = (lhs.y * rhs.zwxy) * {+,+,-,-}
3408    /// T4 = (lhs.z * rhs.yxwz) * {-,+,+,-}
3409    /// T1 + T2 + T3 + T4
3410    /// ```
3411    fn quat4_product(self, other: Self) -> Self;
3412
3413    /// Quaternion-vector multiplication.
3414    ///
3415    /// This is optimized to work best on various SIMD architectures. On
3416    /// architectures with permute/shuffle instructions, it uses the
3417    /// Double-Cross (Giesen) method. On architectures without such instructions,
3418    /// it falls back to the standard method of two dot products
3419    /// and a single cross product. This is because cross products require
3420    /// several shuffles/permutations to compute efficiently with SIMD.
3421    ///
3422    /// The `DOP` generic parameter indicates whether to use the
3423    /// "Difference of Products" method for computing the cross product(s),
3424    /// which can be more accurate in some cases, but _requires_
3425    /// hardware fused multiply-add instructions to be efficient.
3426    ///
3427    /// If you want the best performance, set `DOP` to `false`.\
3428    /// If you want the best accuracy or have FMA support, set `DOP` to `true`.
3429    fn quat4_vec3_product<const DOP: bool>(self, vec: Self) -> Self;
3430
3431    /// Rotation matrix of a **unit** quaternion as 3 registers; the 4th lane of
3432    /// each is unspecified.
3433    ///
3434    /// `COLUMN_MAJOR` picks the storage: the rotation's columns when `true`, its
3435    /// rows when `false` (i.e. the transpose). The choice is free - only the
3436    /// compile-time sign masks differ.
3437    ///
3438    /// Trig-free - the entries are pairwise products of `{x, y, z, w}`, no
3439    /// `sin`/`cos`/`sqrt`. The quaternion is assumed normalized.
3440    ///
3441    /// To rotate many vectors by one quaternion, convert once here and batch via
3442    /// [`mat3_vec3_product`](LinAlg3Vector::mat3_vec3_product) with the matching
3443    /// `COLUMN_MAJOR` - cheaper than a per-vector
3444    /// [`quat4_vec3_product`](Self::quat4_vec3_product) for large `N`.
3445    fn quat_to_mat3<const COLUMN_MAJOR: bool>(self) -> [Self; 3];
3446
3447    /// Homogeneous 4x4 rotation matrix of a **unit** quaternion: the
3448    /// [`quat_to_mat3`](Self::quat_to_mat3) rotation with each rotation
3449    /// register's 4th lane zeroed and a `[0, 0, 0, 1]` 4th register.
3450    /// `COLUMN_MAJOR` is forwarded to `quat_to_mat3`.
3451    fn quat_to_mat4<const COLUMN_MAJOR: bool>(self) -> [Self; 4];
3452
3453    /// 4x4 Matrix Transpose.
3454    fn mat4_transpose(m: &[Self; 4]) -> [Self; 4];
3455
3456    /// 4x4 Matrix-Vector multiplication, assuming `self` as the vector.
3457    ///
3458    /// The `COLUMN_MAJOR` generic parameter indicates whether the matrix
3459    /// is stored in column-major order (`true`) or row-major order (`false`).
3460    ///
3461    /// If the matrix is **NOT** in column-major order, it will need to be
3462    /// transposed before the actual multiplication, which will incur a performance penalty.
3463    ///
3464    /// NOTE: If you want to multiply 4 vectors by the same **column-major** matrix, consider using
3465    /// [`LinAlg4Vector::mat4_product`] instead. It is conceptually the same as multiplying each
3466    /// vector individually, but can take advantage of SIMD optimizations better.
3467    fn mat4_vec4_product<const COLUMN_MAJOR: bool>(self, m: &[Self; 4]) -> Self;
3468
3469    /// 4x4 Matrix-Vector3 multiplication, optimized for the case where the vector is a 3D coordinate
3470    /// (i.e., the 4th lane is ignored).
3471    ///
3472    /// The `COLUMN_MAJOR` generic parameter indicates whether the matrix
3473    /// is stored in column-major order (`true`) or row-major order (`false`).
3474    ///
3475    /// If the matrix is **NOT** in column-major order, it will need to be
3476    /// transposed before the actual multiplication, which will incur a performance penalty.
3477    fn mat4_vec3_product<const COLUMN_MAJOR: bool>(self, m: &[Self; 4]) -> Self;
3478
3479    /// 4x4 matrix multiplied with `N` 3D vectors (small-`N` batch; see
3480    /// [`mat4_vec4_product_array`](Self::mat4_vec4_product_array)).
3481    fn mat4_vec3_product_array<const COLUMN_MAJOR: bool, const N: usize>(
3482        m: &[Self; 4],
3483        vectors: &[Self; N],
3484    ) -> [Self; N];
3485
3486    /// 4x4 Matrix-Point3 multiplication, optimized for the case where the input 3D value is a
3487    /// point of homogenous coordinates (i.e. 4th lane is 1.0).
3488    ///
3489    /// The `COLUMN_MAJOR` generic parameter indicates whether the matrix
3490    /// is stored in column-major order (`true`) or row-major order (`false`).
3491    ///
3492    /// If the matrix is **NOT** in column-major order, it will need to be
3493    /// transposed before the actual multiplication, which will incur a performance penalty.
3494    fn mat4_point3_product<const COLUMN_MAJOR: bool>(self, m: &[Self; 4]) -> Self;
3495
3496    /// 4x4 Matrix multiplied with `N` 3D points (small-`N` batch).
3497    fn mat4_point3_product_array<const COLUMN_MAJOR: bool, const N: usize>(
3498        m: &[Self; 4],
3499        points: &[Self; N],
3500    ) -> [Self; N];
3501
3502    /// 4x4 Matrix-Matrix multiplication.
3503    ///
3504    /// If `COLUMN_MAJOR` is `false`, the matrices are assumed to be in row-major order,
3505    /// and the order of the multiplication will become `rhs * lhs` to account for that.
3506    /// This is mathematically equivalent to transposing both matrices, performing
3507    /// the multiplication, and then transposing the result, but is obviously more efficient.
3508    ///
3509    /// NOTE: When operating in column-major mode (`COLUMN_MAJOR = true`), the multiplication
3510    /// is effectively:
3511    /// ```text
3512    /// C0 = mat4_vec4_product(lhs, R0)
3513    /// C1 = mat4_vec4_product(lhs, R1)
3514    /// C2 = mat4_vec4_product(lhs, R2)
3515    /// C3 = mat4_vec4_product(lhs, R3)
3516    /// ```
3517    ///
3518    /// and is therefore, in **column-major order**, useful for transforming 4 vectors
3519    /// by the same matrix, but capable of being optimized better than doing
3520    /// 4 individual matrix-vector multiplications.
3521    fn mat4_product<const COLUMN_MAJOR: bool>(lhs: &[Self; 4], rhs: &[Self; 4]) -> [Self; 4];
3522
3523    /// Transform `N` vectors by a single 4x4 matrix, returning the transformed array.
3524    ///
3525    /// Intended for **small** `N` (a handful of points): the array is taken and
3526    /// returned **by value** and the loop fully unrolls, so a large `N` will
3527    /// bloat code size and stack usage. For large or dynamic counts, loop
3528    /// [`mat4_vec4_product`](Self::mat4_vec4_product) over a slice instead.
3529    ///
3530    /// Row-major matrices are transposed once up front (amortized over `N`).
3531    /// Backends with a true double-width register transform two vectors per pass.
3532    fn mat4_vec4_product_array<const COLUMN_MAJOR: bool, const N: usize>(
3533        m: &[Self; 4],
3534        vectors: &[Self; N],
3535    ) -> [Self; N];
3536
3537    /// In-place 4x4 Matrix inversion; **returns the determinant**.
3538    ///
3539    /// An exactly-zero determinant leaves the matrix untouched; a near-zero
3540    /// (ill-conditioned) determinant gives a finite but unreliable result, so
3541    /// inspect the returned determinant before trusting the matrix.
3542    fn mat4_inverse_inplace(m: &mut [Self; 4]) -> Self::Element;
3543
3544    /// Compute the determinant of a 4x4 matrix without inverting it.
3545    fn mat4_det(m: &[Self; 4]) -> Self::Element;
3546
3547    /// 4x4 Matrix inversion.
3548    ///
3549    /// Returns `Some(inverted_matrix)`, or `None` if the matrix is exactly
3550    /// singular. Consider [`Vector::mat4_inverse_inplace`] (which hands back the
3551    /// determinant) to avoid the copy and to use a custom tolerance.
3552    #[inline(always)]
3553    fn mat4_inverse(m: &[Self; 4]) -> Option<[Self; 4]> {
3554        let mut mat = *m;
3555
3556        if crate::likely(Self::mat4_inverse_inplace(&mut mat) != Self::Element::ZERO) {
3557            Some(mat)
3558        } else {
3559            None
3560        }
3561    }
3562}