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.
1371    ///
1372    /// Lane count is preserved; only the element type changes. The cast may
1373    /// be widening, narrowing, signed/unsigned, or float/int. Out-of-range
1374    /// float-to-int conversions follow the same saturating behavior as
1375    /// scalar `as` on the host backend.
1376    #[inline(always)] fn cast<INTO>(self) -> INTO
1377    where
1378        INTO: CastVector<Self>,
1379    {
1380        INTO::cast_from(self)
1381    }
1382
1383    /// Fast numeric cast to another vector type.
1384    ///
1385    /// Equivalent to [`cast`](Self::cast) when the backend has no faster path,
1386    /// but may relax IEEE corner cases (NaN propagation, out-of-range
1387    /// float-to-int handling) in exchange for fewer instructions.
1388    ///
1389    /// Use [`cast`](Self::cast) when you need the documented `as` semantics
1390    /// exactly; use this when you have already ruled out problematic inputs.
1391    #[inline(always)] fn fast_cast<INTO>(self) -> INTO
1392    where
1393        INTO: CastVector<Self>,
1394    {
1395        INTO::fast_cast_from(self)
1396    }
1397
1398    /// Reinterpret the bits of this vector as another vector type of the same
1399    /// size and lane count.
1400    ///
1401    /// This is a zero-cost transmute; no conversion is performed. Typical use
1402    /// is moving between a float vector and its integer "bits" vector for
1403    /// bit-level manipulation.
1404    #[inline(always)] fn into_bits<INTO>(self) -> INTO
1405    where
1406        INTO: BitCastVector<Self>,
1407    {
1408        INTO::from_bits(self)
1409    }
1410
1411    /// Narrowing cast that saturates (clamps) out-of-range values to the
1412    /// destination element range, rather than wrapping like [`cast`](Self::cast).
1413    ///
1414    /// Only resolves for narrowing, same-signedness integer conversions
1415    /// (`i64 -> ... -> i8`, `u64 -> ... -> u8`); widening or sign-changing
1416    /// casts have no `SaturatingCastVector` impl and must use [`cast`](Self::cast).
1417    /// See [`SaturatingCastVector`].
1418    #[inline(always)] fn saturating_cast<INTO>(self) -> INTO
1419    where
1420        INTO: SaturatingCastVector<Self>,
1421    {
1422        INTO::saturating_cast_from(self)
1423    }
1424}
1425
1426/// Bitwise operations over the lanes of a vector: `&`, `|`, `^`, `!`,
1427/// `bitandnot`, and the arbitrary three-input [`ternlog`](Self::ternlog).
1428///
1429/// Implemented by integer and mask vectors. Float vectors have no direct bitwise
1430/// ops, so reach their bits through [`FloatVectorWithBits`] first.
1431///
1432/// Note that `a.bitandnot(b)` is `a & !b` at this layer.
1433#[rustfmt::skip] #[thermite_macros::vector_trait]
1434#[diagnostic::on_unimplemented(
1435    message = "`{Self}` does not support bitwise vector operations",
1436    label = "no `&`, `|`, `^`, `!`, andnot, or ternlog",
1437    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."
1438)]
1439pub trait BitwiseVector:
1440    GenericVector
1441    + ops::BitAndMasked<Self::Mask, Self, Output = Self>
1442    + ops::BitAndAssignMasked<Self::Mask, Self>
1443    + ops::BitAndNotMasked<Self::Mask, Self, Output = Self>
1444    + ops::BitAndNotAssignMasked<Self::Mask, Self>
1445    + ops::BitOrMasked<Self::Mask, Self, Output = Self>
1446    + ops::BitOrAssignMasked<Self::Mask, Self>
1447    + ops::BitXorMasked<Self::Mask, Self, Output = Self>
1448    + ops::BitXorAssignMasked<Self::Mask, Self>
1449    + ops::NotMasked<Self::Mask, Output = Self>
1450{
1451    /// Computes an arbitrary bitwise boolean function of three inputs (`a`, `b`, `c`)
1452    /// based on the truth table specified by `IMM`.
1453    ///
1454    /// This function is a "programmable logic gate". It applies the logic defined in `IMM`
1455    /// to every bit of the inputs in parallel.
1456    ///
1457    /// # How to Calculate `IMM`
1458    /// The easiest way to find the correct `IMM` value is to perform your desired boolean
1459    /// logic on these three specific "Magic Constants":
1460    ///
1461    /// * **A** = `0xF0` (Binary `11110000`)
1462    /// * **B** = `0xCC` (Binary `11001100`)
1463    /// * **C** = `0xAA` (Binary `10101010`)
1464    ///
1465    /// ## Example: `(A OR B) XOR C`
1466    /// 1. `A | B` = `0xF0 | 0xCC` = `0xFC`
1467    /// 2. `Result ^ C` = `0xFC ^ 0xAA` = `0x56`
1468    /// 3. Therefore, `IMM = 0x56`.
1469    ///
1470    /// You can also use the [`ternlog_imm!`](crate::ternlog_imm) macro to compute
1471    /// this at compile time.
1472    ///
1473    /// # Visualization using Disjunction Normal Form (DNF)
1474    /// The constants `0xF0`, `0xCC`, and `0xAA` simply form a parallel truth table
1475    /// for all 8 possible combinations of 3 bits:
1476    ///
1477    /// |  A  |  B  |  C  |  Bit Index  |  Term Logic (Minterm) |
1478    /// |:---:|:---:|:---:|:-----------:|:---------------------:|
1479    /// |  0  |  0  |  0  |      0      | ~A & ~B & ~C          |
1480    /// |  0  |  0  |  1  |      1      | ~A & ~B &  C          |
1481    /// |  0  |  1  |  0  |      2      | ~A &  B & ~C          |
1482    /// |  0  |  1  |  1  |      3      | ~A &  B &  C          |
1483    /// |  1  |  0  |  0  |      4      |  A & ~B & ~C          |
1484    /// |  1  |  0  |  1  |      5      |  A & ~B &  C          |
1485    /// |  1  |  1  |  0  |      6      |  A &  B & ~C          |
1486    /// |  1  |  1  |  1  |      7      |  A &  B &  C          |
1487    ///
1488    /// If `IMM = 0x88` (Bit 3 and 7 set), the logic is:
1489    /// - Bit 3 (0, 1, 1): `~A & B & C`
1490    /// - Bit 7 (1, 1, 1): `A & B & C`
1491    ///
1492    /// As raw DNF, this becomes: `(~A & B & C) | (A & B & C)`.\
1493    /// `~A` and `A` cancel out, simplifying to `B & C`.
1494    ///
1495    /// For each bit set in IMM, we effectively bitwise-OR each corresponding minterm.
1496    ///
1497    /// # Common Immediate Values
1498    /// | Logic | Immediate | Description |
1499    /// | :--- | :--- | :--- |
1500    /// | `A ^ B ^ C` | `0x96` | **3-Way XOR** (Parity) |
1501    /// | `(A & B) OR (~A & C)` | `0xCA` | **Bitwise Select** (If A=1 use B, else use C) |
1502    /// | `(A & B) OR (A & C) OR (B & C)` | `0xE8` | **Majority** (True if 2+ inputs are 1) |
1503    /// | `A OR B OR C` | `0xFE` | **3-Way OR** |
1504    /// | `A ? B : 0` | `0xA0` | **Mask** (A & B) |
1505    ///
1506    /// # Performance Note
1507    /// Since `IMM` is a compile-time constant, the compiler will optimize this function
1508    /// into the most efficient sequence of native instructions (AND, OR, XOR, NOT)
1509    /// for your specific architecture. If using AVX512, there actually exists a single
1510    /// instruction for this.
1511    #[conditional] fn ternlog<const IMM: i32>(a: Self, b: Self, c: Self) -> Self;
1512
1513    /// Two-input version of [`ternlog`](Self::ternlog).
1514    ///
1515    /// Computes an arbitrary bitwise boolean function of two inputs (`a`, `b`)
1516    /// based on the 4-bit truth table specified by the low nibble of `IMM`.
1517    /// Bit `i` of `IMM` selects the output when `(a, b)` equals the binary
1518    /// representation of `i`. As with `ternlog`, the magic constants are
1519    /// `A = 0xC` (`1100`) and `B = 0xA` (`1010`); evaluate your desired logic
1520    /// against them to obtain `IMM`. For example, `A & B == 0x8`, `A | B == 0xE`,
1521    /// `A ^ B == 0x6`, `!A == 0x3`.
1522    ///
1523    /// Since `IMM` is a compile-time constant, the compiler lowers this to
1524    /// the most efficient native instruction sequence for the target ISA.
1525    #[conditional] fn bilog<const IMM: i32>(a: Self, b: Self) -> Self;
1526}
1527
1528/// Shifts and rotates over the lanes of an integer vector, by an immediate, by a
1529/// runtime scalar, or by a per-lane count.
1530///
1531/// `<<` and `>>` are the operator forms. **`>>` is a logical shift even on a
1532/// signed vector**, since the operator traits are shared with the unsigned
1533/// vectors. Sign-filling shifts live on [`SignedIntegerVector`] as
1534/// [`srai`](SignedIntegerVector::srai) / [`sra`](SignedIntegerVector::sra) /
1535/// [`srav`](SignedIntegerVector::srav).
1536///
1537/// Per-lane variable shifts ([`shlv`](Self::shlv) and friends) are one
1538/// instruction where the ISA has them (AVX2 `vpsllvd`) and a lane walk where it
1539/// does not, which [`HAS_TRUE_SHIFTV`](Self::HAS_TRUE_SHIFTV) reports.
1540#[rustfmt::skip] #[thermite_macros::vector_trait]
1541#[diagnostic::on_unimplemented(
1542    message = "`{Self}` does not support bit-shift vector operations",
1543    label = "no `<<`, `>>`, rotate, or byte-shift",
1544    note = "`BitshiftVector` is implemented by integer vectors (`Vector<i32>`, `Vector<u8>`, `i32xN`, ...). Float and mask vectors do not have shifts."
1545)]
1546pub trait BitshiftVector:
1547    BitwiseVector
1548    + ops::ShrMasked<Self::Mask, Self::Unsigned, Output = Self>
1549    + ops::ShrAssignMasked<Self::Mask, Self::Unsigned>
1550    + ops::ShlMasked<Self::Mask, Self::Unsigned, Output = Self>
1551    + ops::ShlAssignMasked<Self::Mask, Self::Unsigned>
1552    + ops::ShrMasked<Self::Mask, u32, Output = Self>
1553    + ops::ShrAssignMasked<Self::Mask, u32>
1554    + ops::ShlMasked<Self::Mask, u32, Output = Self>
1555    + ops::ShlAssignMasked<Self::Mask, u32>
1556{
1557    /// `true` if the backend has a true per-lane variable shift instruction
1558    /// (e.g. AVX2 `vpsllvd`). When `false`, [`shlv`](Self::shlv) /
1559    /// [`shrv`](Self::shrv) are emulated and may be slower than splatting a
1560    /// scalar shift count through [`shli`](Self::shli) / [`shri`](Self::shri).
1561    const HAS_TRUE_SHIFTV: bool;
1562
1563    /// `true` if the backend can byte-shift the entire vector as a single
1564    /// large integer at register widths above 128 bits without lane-boundary
1565    /// stitching. When `false`, [`bshli`](Self::bshli) / [`bshri`](Self::bshri)
1566    /// on wider vectors are emulated via shuffles.
1567    const HAS_WIDE_BYTE_SHIFTS: bool;
1568
1569    /// Treats the entire vector as a single large integer and shifts left by the immediate value
1570    /// number of BYTES. Not bits, bytes.
1571    ///
1572    /// Bits shifted out at the high end are discarded; the low end is zero-filled.
1573    #[conditional] fn bshli<const I: i32>(self) -> Self;
1574
1575    /// Treats the entire vector as a single large integer and shifts right by the immediate value
1576    /// number of BYTES. Not bits, bytes.
1577    ///
1578    /// Bits shifted out at the low end are discarded; the high end is zero-filled.
1579    #[conditional] fn bshri<const I: i32>(self) -> Self;
1580
1581    /// For each lane in the vector, shift left by the immediate value.
1582    #[conditional] fn shli<const I: i32>(self) -> Self;
1583
1584    /// For each lane in the vector, shift right by the immediate value.
1585    #[conditional] fn shri<const I: i32>(self) -> Self;
1586
1587    /// For each lane in the vector, shift left by the given value.
1588    #[conditional] fn shlv(self, counts: Self::Unsigned) -> Self;
1589
1590    /// For each lane in the vector, shift right by the given value.
1591    #[conditional] fn shrv(self, counts: Self::Unsigned) -> Self;
1592
1593    /// For each element in the vector, rotate the bits to the left by the given
1594    /// number of bits.
1595    #[conditional] fn rol(self, shift: u32) -> Self;
1596    /// For each element in the vector, rotate the bits to the right by the given
1597    /// number of bits.
1598    #[conditional] fn ror(self, shift: u32) -> Self;
1599    /// For each element in the vector, rotate the bits to the left by the immediate
1600    /// value number of bits.
1601    #[conditional] fn roli<const I: i32>(self) -> Self;
1602    /// For each element in the vector, rotate the bits to the right by the immediate
1603    /// value number of bits.
1604    #[conditional] fn rori<const I: i32>(self) -> Self;
1605
1606    /// For each element in the vector, rotate the bits to the left by the given
1607    /// number of bits in the corresponding lane of `counts`.
1608    #[conditional] fn rolv(self, counts: Self::Unsigned) -> Self;
1609
1610    /// For each element in the vector, rotate the bits to the right by the given
1611    /// number of bits in the corresponding lane of `counts`.
1612    #[conditional] fn rorv(self, counts: Self::Unsigned) -> Self;
1613
1614    /// For each element in the vector, reverse the bits of that element.
1615    #[conditional] fn reverse_bits(self) -> Self;
1616}
1617
1618/// Per-lane numeric conversion between vector types.
1619///
1620/// Implementing `CastVector<FROM>` for `Self` means a `FROM` value can be
1621/// converted into `Self` with the same semantics as Rust's `as` operator on
1622/// the underlying scalar elements. Most users should call
1623/// [`GenericVector::cast`] rather than these methods directly.
1624pub trait CastVector<FROM: Sized>: Sized {
1625    /// Convert a vector of type `FROM` into `Self`, lane-by-lane, using `as`
1626    /// semantics on each element.
1627    fn cast_from(from: FROM) -> Self;
1628
1629    /// Convert this vector into a vector of type `FROM`, lane-by-lane.
1630    fn cast_into(self) -> FROM;
1631
1632    /// Like [`cast_from`](Self::cast_from), but may take a faster path that
1633    /// relaxes IEEE corner cases. See [`GenericVector::fast_cast`].
1634    #[inline(always)]
1635    fn fast_cast_from(from: FROM) -> Self {
1636        Self::cast_from(from)
1637    }
1638
1639    /// Like [`cast_into`](Self::cast_into), but may take a faster path that
1640    /// relaxes IEEE corner cases. See [`GenericVector::fast_cast`].
1641    #[inline(always)]
1642    fn fast_cast_into(self) -> FROM {
1643        Self::cast_into(self)
1644    }
1645}
1646
1647/// Zero-cost bit-level reinterpretation between vector types of the same
1648/// size and lane count.
1649///
1650/// Unlike [`CastVector`], no numeric conversion is performed: the underlying
1651/// bits are reinterpreted as the destination element type. Typical use is
1652/// moving between a float vector and its integer "bits" vector.
1653pub trait BitCastVector<FROM: Sized>: Sized {
1654    /// Reinterpret the bit pattern of `bits` as a value of `Self`.
1655    fn from_bits(bits: FROM) -> Self;
1656}
1657
1658/// Vector-layer mirror of [`SaturatingCastRegister`](crate::register::SaturatingCastRegister):
1659/// a narrowing, same-signedness cast that clamps out-of-range values to the
1660/// destination element range instead of wrapping like [`CastVector`].
1661///
1662/// Implemented only for narrowing same-sign integer pairs (`i64 -> ... -> i8`,
1663/// `u64 -> ... -> u8`, including skip-level pairs). Widening and sign-changing
1664/// conversions are not saturating and go through [`CastVector`]. Most users
1665/// reach this through [`GenericVector::saturating_cast`] rather than naming the
1666/// trait directly.
1667///
1668/// Blanket-implemented for every `Vector<INTO>` whose register implements
1669/// [`SaturatingCastRegister<FROM>`](crate::register::SaturatingCastRegister).
1670pub trait SaturatingCastVector<FROM: Sized>: Sized {
1671    /// Narrow `from` into `Self`, clamping each lane to `Self`'s element range.
1672    fn saturating_cast_from(from: FROM) -> Self;
1673}
1674
1675/// A `u16`/`u8` integer vector reinterpreted as a vector of *packed floats* (format `S`: fp16,
1676/// bfloat16, the fp8 variants, ...), transcodable to and from the wider `f32` vector `F` of the
1677/// same lane count.
1678///
1679/// This is the vector-layer mirror of
1680/// [`PackedFloatRegister`](crate::register::PackedFloatRegister): `Self` is the `Vector<u16/u8
1681/// register>` and `F` is the matching `Vector<f32 register>`. Both directions are exact for the
1682/// decode (every value of these sub-`f32` formats is representable in `f32`) and round-to-nearest
1683/// for the encode; backends use hardware (F16C `vcvtph2ps`) where available and a generic
1684/// branchless fallback otherwise.
1685///
1686/// Blanket-implemented for every `Vector<R>` whose register implements `PackedFloatRegister<S,
1687/// FR>`, so e.g. `u16x8<S>: PackedFloatVector<Fp16, f32x8<S>>` holds wherever the register does.
1688///
1689/// ```
1690/// # use thermite::prelude::*;
1691/// # use thermite::element::float::spec::Fp16;
1692/// # use thermite::vector::PackedFloatVector;
1693/// fn widen<U, F>(halves: U) -> F
1694/// where
1695///     U: PackedFloatVector<Fp16, F>,
1696/// {
1697///     halves.unpack()
1698/// }
1699/// ```
1700pub trait PackedFloatVector<S: crate::element::float::spec::FloatSpec, F>: GenericVector {
1701    /// Encode the `f32` vector `values` into this packed format (round to nearest, ties to even;
1702    /// overflow / non-finite handled per the format `S`).
1703    fn pack(values: F) -> Self;
1704
1705    /// Decode this packed-float vector into the `f32` vector it represents (exact).
1706    fn unpack(self) -> F;
1707}
1708
1709/// A `u8` vector whose absolute differences can be summed in groups of 2 byte-lanes into
1710/// the `u16` vector `W` (same total width, `LANES / 2` output lanes).
1711///
1712/// Vector-layer mirror of [`Sad16Register`](crate::register::Sad16Register);
1713/// blanket-implemented for every `Vector<R>` whose register implements it. Each output
1714/// lane is at most `510`. There is no accumulating form - a `u16` lane saturates after
1715/// ~128 accumulations; use [`Sad32Vector`] / [`Sad64Vector`] to reduce over a long run.
1716pub trait Sad16Vector<W>: GenericVector {
1717    /// Sum of absolute differences over each aligned pair of byte lanes.
1718    fn sad16(self, other: Self) -> W;
1719}
1720
1721/// A `u8` vector whose absolute differences can be summed in groups of 4 byte-lanes into
1722/// the `u32` vector `W` (same total width, `LANES / 4` output lanes).
1723///
1724/// Vector-layer mirror of [`Sad32Register`](crate::register::Sad32Register). Each output
1725/// lane is at most `1020`, so [`sad32_accum`](Self::sad32_accum) absorbs ~4.2e6
1726/// accumulations before overflow.
1727pub trait Sad32Vector<W>: GenericVector {
1728    /// Sum of absolute differences over each aligned group of 4 byte lanes.
1729    fn sad32(self, other: Self) -> W;
1730
1731    /// `acc + self.sad32(other)` - the accumulate step of a blocked SAD loop.
1732    fn sad32_accum(self, acc: W, other: Self) -> W;
1733}
1734
1735/// A `u8` vector whose absolute differences can be summed in groups of 8 byte-lanes into
1736/// the `u64` vector `W` (same total width, `LANES / 8` output lanes) - x86 `PSADBW`
1737/// semantics.
1738///
1739/// Vector-layer mirror of [`Sad64Register`](crate::register::Sad64Register). The `u64`
1740/// lanes are accumulation headroom (each result is at most `2040`), so the intended shape
1741/// of a byte-buffer reduction is to [`sad64_accum`](Self::sad64_accum) through the loop
1742/// and reduce horizontally exactly once at the end:
1743///
1744/// ```ignore
1745/// let mut acc = W::ZERO;
1746/// for (a, b) in blocks { acc = a.sad64_accum(acc, b); }
1747/// let total = acc.sum_elements();
1748/// ```
1749pub trait Sad64Vector<W>: GenericVector {
1750    /// Sum of absolute differences over each aligned group of 8 byte lanes.
1751    fn sad64(self, other: Self) -> W;
1752
1753    /// `acc + self.sad64(other)` - the accumulate step of a blocked SAD loop.
1754    fn sad64_accum(self, acc: W, other: Self) -> W;
1755}
1756
1757/// Lanes of a vector partitioned into groups of equal value, produced by
1758/// [`group_by_value`](PartialOrdVector::group_by_value).
1759///
1760/// Each call to [`next_group`](Self::next_group) yields one distinct value and
1761/// the mask of lanes holding it; groups come out in order of first occurrence,
1762/// and every selected lane is yielded exactly once. That turns a divergent
1763/// packet, whose lanes want different work, into a short sequence of uniform
1764/// sub-packets.
1765///
1766/// The inherent [`next_group`](Self::next_group) is the primary interface: a
1767/// plain `while let` loop needs no trait in scope and inlines predictably inside
1768/// `#[target_feature]` bodies. [`Iterator`] is implemented on top of it, so
1769/// `for` loops work too.
1770///
1771/// ```ignore
1772/// // Shade a ray packet one geometry at a time.
1773/// let mut groups = geom_ids.group_by_value(active);
1774/// while let Some((geom_id, lanes)) = groups.next_group() {
1775///     shade(geom_id, lanes);
1776/// }
1777/// ```
1778///
1779/// Cost is proportional to the number of *distinct* values, not the lane count:
1780/// roughly a broadcast, a compare, and two mask ops per group. A uniform packet
1781/// costs one iteration.
1782#[derive(Debug, Clone, Copy)]
1783pub struct ValueGroups<V: PartialOrdVector> {
1784    value: V,
1785    remaining: V::Mask,
1786}
1787
1788impl<V: PartialOrdVector> ValueGroups<V> {
1789    /// The next distinct value and the mask of remaining lanes holding it, or
1790    /// `None` once every selected lane has been yielded.
1791    #[inline(always)]
1792    pub fn next_group(&mut self) -> Option<(V::Element, V::Mask)> {
1793        let lane = self.remaining.first_set()?;
1794
1795        // `broadcastv` rather than `splat(extractv(..))`: one register op that
1796        // backends already specialize, instead of a lane -> scalar -> lane
1797        // round trip through memory.
1798        let group = self.remaining & self.value.cmp_eq(self.value.broadcastv(lane));
1799        let value = self.value.extractv(lane);
1800
1801        self.remaining = crate::vector::ops::BitAndNot::bitandnot(self.remaining, group);
1802
1803        Some((value, group))
1804    }
1805
1806    /// Lanes not yet yielded, so a caller can stop part-way and keep the rest.
1807    #[inline(always)]
1808    pub fn remaining(&self) -> V::Mask {
1809        self.remaining
1810    }
1811
1812    /// Whether every selected lane has been yielded.
1813    #[inline(always)]
1814    pub fn is_empty(&self) -> bool {
1815        self.remaining.none()
1816    }
1817}
1818
1819impl<V: PartialOrdVector> Iterator for ValueGroups<V> {
1820    type Item = (V::Element, V::Mask);
1821
1822    #[inline(always)]
1823    fn next(&mut self) -> Option<Self::Item> {
1824        self.next_group()
1825    }
1826}
1827
1828/// Per-lane comparison producing a [`Mask`](GenericVector::Mask).
1829///
1830/// Each comparison returns a mask whose lanes are `true` where the predicate
1831/// held for the corresponding lane pair and `false` otherwise. The mask can
1832/// then be used with [`select`](crate::mask::GenericMask::select),
1833/// `_c`/`_m`/`_z` masked variants, or reduced via
1834/// [`all`](crate::mask::GenericMask::all) /
1835/// [`any`](crate::mask::GenericMask::any).
1836///
1837/// For floating-point vectors, NaN compares unequal to everything, so e.g.
1838/// `cmp_lt(x, NaN)` is always `false`, matching the `<` operator on `f32`/`f64`.
1839#[diagnostic::on_unimplemented(
1840    message = "`{Self}` does not support lane-wise comparisons",
1841    label = "no `cmp_lt` / `cmp_le` / `cmp_gt` / `cmp_ge` / `cmp_eq` / `cmp_ne`",
1842    note = "`PartialOrdVector` turns lane-wise comparisons into a `Mask`; it is implemented by all numeric vectors (integer and float)."
1843)]
1844pub trait PartialOrdVector: GenericVector + PartialEq {
1845    /// Partition the lanes selected by `valid` into groups of equal value.
1846    ///
1847    /// See [`ValueGroups`] for the loop shape and cost. Pass
1848    /// `Self::Mask::TRUTHY` to group every lane.
1849    #[inline(always)]
1850    fn group_by_value(self, valid: Self::Mask) -> ValueGroups<Self> {
1851        ValueGroups {
1852            value: self,
1853            remaining: valid,
1854        }
1855    }
1856
1857    /// Lane-wise `self < other`.
1858    fn cmp_lt(self, other: Self) -> Self::Mask;
1859    /// Lane-wise `self <= other`.
1860    fn cmp_le(self, other: Self) -> Self::Mask;
1861    /// Lane-wise `self > other`.
1862    fn cmp_gt(self, other: Self) -> Self::Mask;
1863    /// Lane-wise `self >= other`.
1864    fn cmp_ge(self, other: Self) -> Self::Mask;
1865    /// Lane-wise `self == other`.
1866    fn cmp_eq(self, other: Self) -> Self::Mask;
1867    /// Lane-wise `self != other`.
1868    fn cmp_ne(self, other: Self) -> Self::Mask;
1869}
1870
1871/// Vectors that support arithmetic and comparison operations on their elements.
1872///
1873/// This trait sits between [`PartialOrdVector`] and the more specific
1874/// [`SignedVector`] / [`IntegerVector`] / [`FloatVector`] traits, and provides
1875/// the operator overloads (`+`, `-`, `*`, `/`, `%`, their `*Assign` variants,
1876/// and the masked `_c`/`_m`/`_z` forms via [`ops`]).
1877///
1878/// # Overflow semantics
1879///
1880/// **For integer element types, the basic arithmetic operators (`+`, `-`, `*`,
1881/// `/`, `%`) are wrapping on overflow.** This matches the behavior of every
1882/// SIMD ISA (`paddd`, `pmulld`, etc. all wrap silently) and avoids per-lane
1883/// panics inside vectorized loops. Concretely, on every backend including the
1884/// scalar reference backend, `Vector::<i32x4>::splat(i32::MAX) + Vector::ONE`
1885/// produces `i32::MIN` in every lane rather than panicking.
1886///
1887/// This is intentional and is **not affected by debug vs release builds**: the
1888/// scalar backend uses `wrapping_add` / `wrapping_sub` / `wrapping_mul`
1889/// internally, so the wrapping behavior is consistent across all build
1890/// configurations. If you need saturation or explicit wrapping naming, use
1891/// [`saturating_add`](IntegerVector::saturating_add) /
1892/// [`saturating_sub`](IntegerVector::saturating_sub), or the
1893/// `num_traits::WrappingAdd` / `WrappingSub` / `WrappingMul` impls.
1894///
1895/// Integer division (`/`, `%`) panics on division by zero, matching scalar
1896/// Rust. Float division by zero produces an infinity or NaN per IEEE 754.
1897///
1898/// For float element types, overflow simply produces an infinity per IEEE 754;
1899/// there is nothing to wrap.
1900#[rustfmt::skip] #[thermite_macros::vector_trait]
1901#[diagnostic::on_unimplemented(
1902    message = "`{Self}` does not support arithmetic vector operations",
1903    label = "no `+`, `-`, `*`, `/`, `%`, min/max, or FMA",
1904    note = "`NumericVector` is implemented by numeric vectors - integer (`Vector<i32>`, `i32xN`, ...) and float (`Vector<f32>`, `f32xN`, ...). Masks and bare scalars do not qualify.",
1905    note = "A bare `f32`/`f64` is not a vector: wrap it in `Vector::<f32>::splat(x)` first."
1906)]
1907pub trait NumericVector:
1908    PartialOrdVector<Element: num_traits::NumOps>
1909    + ops::AddMasked<Self::Mask, Self, Output = Self>
1910    + ops::AddAssignMasked<Self::Mask, Self>
1911    + ops::SubMasked<Self::Mask, Self, Output = Self>
1912    + ops::SubAssignMasked<Self::Mask, Self>
1913    + ops::MulMasked<Self::Mask, Self, Output = Self>
1914    + ops::MulAssignMasked<Self::Mask, Self>
1915    + ops::DivMasked<Self::Mask, Self, Output = Self>
1916    + ops::DivAssignMasked<Self::Mask, Self>
1917    + ops::RemMasked<Self::Mask, Self, Output = Self>
1918    + ops::RemAssignMasked<Self::Mask, Self>
1919    + ops::SquareMasked<Self::Mask, Output = Self>
1920    + num_traits::NumOps<Self>
1921    + num_traits::NumAssignOps<Self>
1922    + core::iter::Sum
1923    + core::iter::Product
1924{
1925    /// A vector of the value "0" in the element type.
1926    const ZERO: Self;
1927    /// A vector of the value "1" in the element type.
1928    const ONE: Self;
1929    /// A vector of the value "2" in the element type.
1930    const TWO: Self;
1931
1932    /// A vector of the minimum value the element type of this vector can represent.
1933    const MIN: Self;
1934    /// A vector of the maximum value the element type of this vector can represent.
1935    const MAX: Self;
1936
1937    /// Convert each lane to the companion signed integer type, with `as` semantics -
1938    /// round toward zero, saturating at the bounds, NaN to zero.
1939    ///
1940    /// This is the numeric conversion, *not* a bit reinterpretation; for the bit
1941    /// pattern of a float see [`GenericVector::into_bits`].
1942    ///
1943    /// # Why a method and not a `CastVector` bound
1944    ///
1945    /// A bound would have to be written either as `Self::Signed: CastVector<Self>`,
1946    /// whose impl `Self` type is an associated-type projection and so cannot be
1947    /// written at all, or as `Self: CastVector<Self::Signed>`, which collides with the
1948    /// blanket self-casts the composite types already carry. A method has no coherence
1949    /// surface and every implementor can simply provide it.
1950    fn to_signed_integer(self) -> Self::Signed;
1951
1952    /// Convert each lane from the companion signed integer type, with `as` semantics.
1953    ///
1954    /// For composite element types this produces a value with no imaginary part, no
1955    /// derivative and no error term: an integer carries none of those.
1956    fn from_signed_integer(v: Self::Signed) -> Self;
1957
1958    /// Convert each lane to the companion unsigned integer type, with `as` semantics.
1959    /// See [`to_signed_integer`](Self::to_signed_integer).
1960    fn to_unsigned_integer(self) -> Self::Unsigned;
1961
1962    /// Convert each lane from the companion unsigned integer type, with `as` semantics.
1963    /// See [`from_signed_integer`](Self::from_signed_integer).
1964    fn from_unsigned_integer(v: Self::Unsigned) -> Self;
1965
1966    /// Like [`to_signed_integer`](Self::to_signed_integer), but may relax IEEE corner
1967    /// cases (out-of-range and NaN inputs) for speed. Defaults to the exact form.
1968    #[inline(always)]
1969    fn fast_to_signed_integer(self) -> Self::Signed {
1970        self.to_signed_integer()
1971    }
1972
1973    /// Like [`to_unsigned_integer`](Self::to_unsigned_integer), but may relax IEEE
1974    /// corner cases. Defaults to the exact form.
1975    #[inline(always)]
1976    fn fast_to_unsigned_integer(self) -> Self::Unsigned {
1977        self.to_unsigned_integer()
1978    }
1979
1980    /// For each element in the vector, return a mask indicating whether that element is zero.
1981    fn is_zero(self) -> Self::Mask;
1982
1983    /// Returns `true` if all elements in the vector are zero, `false` otherwise.
1984    ///
1985    /// This can often be more performant than naive comparisons or even `is_zero().all()`
1986    fn is_all_zero(self) -> bool;
1987
1988    /// Return the minimum of two vectors, element-wise.
1989    #[conditional] fn min(self, other: Self) -> Self;
1990
1991    /// Return the maximum of two vectors, element-wise.
1992    #[conditional] fn max(self, other: Self) -> Self;
1993
1994    /// Sort the lanes of this vector in `O` order.
1995    ///
1996    /// Backed by a sorting network where one exists for the lane count, and by
1997    /// a scalar compare-and-swap walk otherwise - see
1998    /// [`NumericRegister::sort_by`](crate::register::NumericRegister::sort_by),
1999    /// which this delegates to so a backend override is picked up here too.
2000    /// The direction is free; see [`crate::sort`].
2001    fn sort_by<O: crate::sort::SortOrder>(self) -> Self;
2002
2003    /// Sort the lanes of a **bitonic** vector in `O` order - one that rises then
2004    /// falls, or a rotation of one.
2005    ///
2006    /// Garbage in, garbage out on non-bitonic input. See
2007    /// [`NumericRegister::bitonic_clean_by`](crate::register::NumericRegister::bitonic_clean_by).
2008    fn bitonic_clean_by<O: crate::sort::SortOrder>(self) -> Self;
2009
2010    /// Sort the lanes ascending. Shorthand for
2011    /// [`sort_by::<Ascending>`](Self::sort_by).
2012    #[inline(always)]
2013    fn sort(self) -> Self {
2014        self.sort_by::<crate::sort::Ascending>()
2015    }
2016
2017    /// Sort the lanes of a **bitonic** vector ascending. Shorthand for
2018    /// [`bitonic_clean_by::<Ascending>`](Self::bitonic_clean_by).
2019    #[inline(always)]
2020    fn bitonic_clean(self) -> Self {
2021        self.bitonic_clean_by::<crate::sort::Ascending>()
2022    }
2023
2024    /// Clamps the elements of the vector between the given minimum and maximum values.
2025    fn clamp(self, min: Self, max: Self) -> Self;
2026
2027    /// Returns the minimum value in the vector.
2028    ///
2029    /// This operation has an `O(log2 n)` complexity to reduce.
2030    fn min_element(self) -> Self::Element;
2031    /// Returns the maximum value in the vector.
2032    ///
2033    /// This operation has an `O(log2 n)` complexity to reduce.
2034    fn max_element(self) -> Self::Element;
2035    /// Returns both the minimum and maximum values in the vector simultaneously.
2036    ///
2037    /// More efficient than calling [`min_element`](NumericVector::min_element) and
2038    /// [`max_element`](NumericVector::max_element) separately when both are needed.
2039    fn min_max_element(self) -> (Self::Element, Self::Element);
2040
2041    /// Returns the indices of the minimum and maximum elements in the vector, respectively.
2042    fn arg_minmax(self) -> (usize, usize);
2043
2044    /// Scales each element in the vector by the given factor.
2045    ///
2046    /// While semantically equivalent to `self * Self::splat(factor)`, this method may be optimized
2047    /// better on certain architectures, such as GPUs.
2048    #[conditional] fn scale(self, factor: Self::Element) -> Self;
2049
2050    /// Sums adjacent lane pairs from `lo` and `hi`, returning a vector of the same width.
2051    ///
2052    /// Output: `[lo[0]+lo[1], lo[2]+lo[3], ..., hi[0]+hi[1], hi[2]+hi[3], ...]`
2053    ///
2054    /// The result is always in strict order: all pair sums from `lo` followed by all pair sums from `hi`.
2055    fn pairwise_sum(lo: Self, hi: Self) -> Self;
2056
2057    /// Like [`pairwise_sum`](NumericVector::pairwise_sum), but may return a relaxed (implementation-defined)
2058    /// lane ordering for performance. Treat this as if randomly shuffling the result of
2059    /// [`pairwise_sum`](NumericVector::pairwise_sum), with better performance than `pairwise_sum`.
2060    ///
2061    /// Prefer this if you are simply summing any adjacent pairs from `lo` and `hi`, and don't
2062    /// care about the exact ordering of the resulting sums.
2063    fn relaxed_pairwise_sum(lo: Self, hi: Self) -> Self;
2064
2065    /// Returns the sum of all elements in the vector.
2066    ///
2067    /// This operation has an `O(log2 n)` complexity to reduce.
2068    fn sum_elements(self) -> Self::Element;
2069
2070    /// Returns the product of all elements in the vector.
2071    ///
2072    /// This operation has an `O(log2 n)` complexity to reduce.
2073    fn prod_elements(self) -> Self::Element;
2074
2075    /// Inclusive forward prefix sum ("running total"): `out[i] = self[0] + .. + self[i]`.
2076    ///
2077    /// Unlike [`sum_elements`](Self::sum_elements), which collapses the register to one
2078    /// scalar, this keeps every partial sum in its own lane - the primitive behind
2079    /// bin offsets and stream-compaction write indices.
2080    ///
2081    /// `O(log2 LANES)` vector ops where the backend has a native cross-register
2082    /// [`align`](GenericVector::align), a sequential lane walk where it does not,
2083    /// chosen at compile time. For a scan over only some lanes, neutralise the rest
2084    /// first: `v.zz(mask).prefix_sum()`.
2085    ///
2086    /// ```
2087    /// use thermite::prelude::*;
2088    /// use thermite::backend::scalar::Scalar;
2089    ///
2090    /// let v = <thermite::simd::i32x4<Scalar>>::new([1, 2, 3, 4]);
2091    /// assert_eq!(v.prefix_sum().into_array(), [1, 3, 6, 10].into());
2092    /// assert_eq!(v.reverse_prefix_sum().into_array(), [10, 9, 7, 4].into());
2093    /// ```
2094    fn prefix_sum(self) -> Self;
2095
2096    /// Inclusive forward prefix minimum: `out[i] = min(self[0], .., self[i])`.
2097    ///
2098    /// See [`prefix_sum`](Self::prefix_sum) for the cost model. With NaN lanes, which
2099    /// operand wins is unspecified (as for [`min`](Self::min) itself); exact and
2100    /// backend-identical otherwise, infinities included.
2101    fn prefix_min(self) -> Self;
2102
2103    /// Inclusive forward prefix maximum: `out[i] = max(self[0], .., self[i])`.
2104    ///
2105    /// See [`prefix_min`](Self::prefix_min) for the NaN caveat.
2106    fn prefix_max(self) -> Self;
2107
2108    /// Inclusive reverse (suffix) sum: `out[i] = self[i] + .. + self[LANES-1]`.
2109    fn reverse_prefix_sum(self) -> Self;
2110
2111    /// Inclusive reverse (suffix) minimum: `out[i] = min(self[i], .., self[LANES-1])`.
2112    ///
2113    /// See [`prefix_min`](Self::prefix_min) for the NaN caveat.
2114    fn reverse_prefix_min(self) -> Self;
2115
2116    /// Inclusive reverse (suffix) maximum: `out[i] = max(self[i], .., self[LANES-1])`.
2117    ///
2118    /// See [`prefix_min`](Self::prefix_min) for the NaN caveat.
2119    fn reverse_prefix_max(self) -> Self;
2120
2121    /// Returns a vector whose every lane equals [`LANES`](GenericVector::LANES),
2122    /// converted into the element type.
2123    ///
2124    /// Equivalent to `Self::splat(Self::LANES as Self::Element)`. Useful for
2125    /// stepping an [`indexed`](Self::indexed) counter forward by one full
2126    /// vector's worth of lanes in tight loops.
2127    fn offset() -> Self;
2128
2129    /// Returns a vector where each lane holds its own index, cast to the
2130    /// element type: `[0, 1, 2, ..., LANES-1]`.
2131    ///
2132    /// This is the typical starting point for index-based vector loops. The
2133    /// counter can be advanced by adding [`offset`](Self::offset).
2134    fn indexed() -> Self;
2135}
2136
2137/// Vectors whose elements can represent negative values.
2138///
2139/// Adds negation, absolute value, sign extraction, and sign-conditional
2140/// selection on top of [`NumericVector`]. Implemented for signed integer and
2141/// floating-point vectors; not for unsigned integer vectors.
2142///
2143/// As with the base [`NumericVector`] operators, unary `-` on a signed integer
2144/// vector is **wrapping**: `-Vector::<i32x4>::splat(i32::MIN)` returns
2145/// `i32::MIN` in every lane rather than panicking.
2146// TODO: Add back in some kind of `Signed` trait requirement for Element?
2147#[rustfmt::skip] #[thermite_macros::vector_trait]
2148#[diagnostic::on_unimplemented(
2149    message = "`{Self}` is not a signed SIMD vector",
2150    label = "no `abs`, `signum`, `copysign`, or unary `-`",
2151    note = "`SignedVector` is implemented by signed integer and floating-point vectors. Unsigned integer vectors (`Vector<u32>`, `u8xN`, ...) are not signed."
2152)]
2153pub trait SignedVector: NumericVector + ops::NegMasked<Self::Mask, Output = Self> {
2154    /// A vector of the value "-1" in the element type.
2155    const NEG_ONE: Self;
2156
2157    /// A vector of the smallest positive (non-zero) value in the element type.
2158    const MIN_POSITIVE: Self;
2159
2160    /// Take the absolute value of the vector, element-wise.
2161    #[conditional] fn abs(self) -> Self;
2162
2163    /// For each element in the vector, return a new vector
2164    /// where each element is either -1 or +1 depending
2165    /// on the sign of the element.
2166    ///
2167    /// For integers, this will also return zero (0) if the
2168    /// element is zero. This matches Rust's behavior for integer
2169    /// `signum`. Floats remain only -1 or +1.
2170    fn signum(self) -> Self;
2171
2172    /// For each element in the vector, set the sign of that
2173    /// element to the sign of the corresponding element in the other vector.
2174    #[conditional] fn copysign(self, sign: Self) -> Self;
2175
2176    /// For each element in the vector, return a mask indicating
2177    /// whether that element is negative.
2178    fn is_positive(self) -> Self::Mask;
2179
2180    /// For each element in the vector, return a mask indicating
2181    /// whether that element is positive.
2182    fn is_negative(self) -> Self::Mask;
2183
2184    /// Based on if self is negative, select between `if_neg` and `if_pos`.
2185    fn select_negative(self, if_neg: Self, if_pos: Self) -> Self;
2186}
2187
2188/// Vectors of integer elements.
2189///
2190/// Adds bitwise shifts (via [`BitshiftVector`]), bit-counting, saturating
2191/// arithmetic, branchfree integer division helpers, and exposes the type of
2192/// the per-divider precomputed structures used for vectorized division.
2193///
2194/// # Wrapping arithmetic
2195///
2196/// The basic operators (`+`, `-`, `*`, their assigning forms, and unary `-`
2197/// for signed integer vectors) **wrap on overflow** on every backend, in both
2198/// debug and release builds. See [`NumericVector`] for the rationale. The
2199/// `num_traits::WrappingAdd` / `WrappingSub` / `WrappingMul` impls are simply
2200/// renames of the operator forms; for explicit saturation use
2201/// [`saturating_add`](Self::saturating_add) /
2202/// [`saturating_sub`](Self::saturating_sub).
2203///
2204/// # Reductions
2205///
2206/// Horizontal reductions ([`sum_elements`](NumericVector::sum_elements),
2207/// [`prod_elements`](NumericVector::prod_elements), [`wrapping_sum`](Self::wrapping_sum),
2208/// [`wrapping_prod`](Self::wrapping_prod)) all wrap on overflow.
2209#[rustfmt::skip] #[thermite_macros::vector_trait]
2210#[diagnostic::on_unimplemented(
2211    message = "`{Self}` is not an integer SIMD vector",
2212    label = "not an integer vector",
2213    note = "`IntegerVector` is implemented by integer vectors (`Vector<i32>`, `Vector<u8>`, `i32xN`, ...). Float vectors implement `FloatVector` instead; convert with `.to_int()` or a cast."
2214)]
2215pub trait IntegerVector:
2216    NumericVector<Element: Denominator>
2217    + BitshiftVector
2218    + ops::DivMasked<Self::Mask, Self::Divider, Output = Self>
2219    + ops::DivMasked<Self::Mask, Self::BranchfreeDivider, Output = Self>
2220    // TODO: Some of these might interfere with the methods of this trait,
2221    // adding ambiguity. See what we can do about that.
2222    + num_traits::Saturating + num_traits::SaturatingAdd
2223    + num_traits::SaturatingSub + num_traits::WrappingMul
2224    + num_traits::WrappingAdd + num_traits::WrappingSub
2225{
2226    /// Precomputed scalar divider used by per-lane division against a
2227    /// runtime-known but loop-invariant divisor. See [`crate::Divider`].
2228    type Divider: Copy;
2229    /// Branchfree variant of [`Divider`](Self::Divider). Slightly slower for
2230    /// some divisors but always emits straight-line code with no conditional
2231    /// branches, which is what you want inside a hot SIMD loop.
2232    type BranchfreeDivider: Copy;
2233    /// Precomputed per-lane divider produced by [`to_divider`](Self::to_divider).
2234    /// Used when each lane needs a different (but loop-invariant) divisor.
2235    type VectorizedDivider: Copy;
2236
2237    /// Multiply two vectors lane-wise and return the *high* half of each
2238    /// double-width product.
2239    ///
2240    /// For signed `i32` lanes the result is `(a as i64 * b as i64) >> 32`;
2241    /// for unsigned `u32` it is the same with `u64`. Together with
2242    /// [`mullo`](Self::mullo) this gives the full double-width product
2243    /// without widening the vector type.
2244    #[conditional] fn mulhi(self, other: Self) -> Self;
2245
2246    /// Multiply two vectors lane-wise and return the *low* half of each
2247    /// product, with wrapping on overflow.
2248    ///
2249    /// This is bit-identical to the `*` operator on integer vectors; the
2250    /// dedicated method exists because some ISAs have specialized
2251    /// low-half-only multiply instructions worth emitting directly.
2252    #[conditional] fn mullo(self, other: Self) -> Self;
2253
2254    // fn wrapping_add(self, other: Self) -> Self;
2255    // fn wrapping_sub(self, other: Self) -> Self;
2256    // fn wrapping_mul(self, other: Self) -> Self;
2257
2258    /// Per-lane saturating addition: instead of wrapping, the result is
2259    /// clamped to the element type's range (`MIN`..=`MAX`) on overflow.
2260    #[conditional] fn saturating_add(self, other: Self) -> Self;
2261
2262    /// Per-lane saturating subtraction: instead of wrapping, the result is
2263    /// clamped to the element type's range (`MIN`..=`MAX`) on overflow.
2264    #[conditional] fn saturating_sub(self, other: Self) -> Self;
2265
2266    /// Horizontal sum of all lanes, wrapping on overflow.
2267    ///
2268    /// Equivalent to [`sum_elements`](NumericVector::sum_elements) on integer
2269    /// vectors; the explicit name documents the wrapping behavior at the
2270    /// callsite.
2271    #[conditional] fn wrapping_sum(self) -> Self::Element;
2272
2273    /// Horizontal product of all lanes, wrapping on overflow.
2274    ///
2275    /// Equivalent to [`prod_elements`](NumericVector::prod_elements); the
2276    /// explicit name documents the wrapping behavior at the callsite.
2277    #[conditional] fn wrapping_prod(self) -> Self::Element;
2278
2279    /// Build a [`Divider`](Self::Divider) for a single scalar divisor `d`,
2280    /// suitable for repeatedly dividing many vectors by the same `d`.
2281    ///
2282    /// Construction is `O(1)` but non-trivial; build once outside the hot
2283    /// loop, then use `vec / divider` inside.
2284    fn create_divider(d: Self::Element) -> Self::Divider;
2285
2286    /// Build a [`BranchfreeDivider`](Self::BranchfreeDivider) for a single
2287    /// scalar divisor `d`. Prefer this over [`create_divider`](Self::create_divider)
2288    /// inside tight SIMD loops where conditional branches would hurt
2289    /// throughput.
2290    fn create_branchfree_divider(d: Self::Element) -> Self::BranchfreeDivider;
2291
2292    /// Use this vector as the denominators for a vectorized division operation.
2293    ///
2294    /// This creates a `VectorDivider` which can then be used to perform
2295    /// vectorized integer division with the `Div` trait. Note that for unsigned
2296    /// integer types, `1` is not a valid denominator and will cause a panic.
2297    ///
2298    /// This operation itself is NOT vectorized and is `O(n)` in the number of lanes.
2299    /// It is designed to be calculated once and then reused for multiple division operations.
2300    ///
2301    /// # Panics
2302    ///
2303    /// If unsigned, integer values of `1` present in the vector
2304    /// denominators will cause a panic.
2305    fn to_divider(self) -> Self::VectorizedDivider;
2306
2307    /// For each element in the vector, count the number of bits that are set to 1.
2308    #[conditional] fn count_ones(self) -> Self;
2309    /// For each element in the vector, count the number of bits that are set to 0.
2310    #[conditional] fn count_zeros(self) -> Self;
2311    /// For each element in the vector, count the number of leading ones.
2312    #[conditional] fn leading_ones(self) -> Self;
2313    /// For each element in the vector, count the number of leading zeros.
2314    #[conditional] fn leading_zeros(self) -> Self;
2315    /// For each element in the vector, count the number of trailing ones.
2316    #[conditional] fn trailing_ones(self) -> Self;
2317    /// For each element in the vector, count the number of trailing zeros.
2318    #[conditional] fn trailing_zeros(self) -> Self;
2319
2320    /// For each lane, how many *earlier* lanes hold the same value:
2321    /// `out[i] == |{ j < i : self[j] == self[i] }|`.
2322    ///
2323    /// Equivalent to AVX-512CD's `conflict(self).count_ones()`. Two things fall
2324    /// out of it:
2325    ///
2326    /// - `count_conflicts().cmp_eq(Self::ZERO)` is the **first-occurrence** mask.
2327    /// - The count is the round number for a conflicting read-modify-write. A
2328    ///   lane of rank `r` is safe to process in round `r`, since every earlier
2329    ///   duplicate has a strictly smaller rank and goes first. That is what
2330    ///   makes a vectorized histogram / SAH-bin increment correct where a plain
2331    ///   scatter would silently drop duplicate writes.
2332    ///
2333    /// Backed by [`IntegerRegister::count_conflicts`](crate::register::IntegerRegister::count_conflicts),
2334    /// so a backend with hardware conflict detection overrides it in one place.
2335    fn count_conflicts(self) -> Self;
2336}
2337
2338/// The operations that need both a sign and integer lanes: arithmetic
2339/// (sign-filling) right shifts, the overflow-free averages, and the rounded
2340/// high-half multiply.
2341///
2342/// The meeting point of [`SignedVector`] and [`IntegerVector`], implemented only
2343/// by vectors of signed integer elements (`Vector<i32>`, `i16xN`, ...).
2344#[rustfmt::skip] #[thermite_macros::vector_trait]
2345#[diagnostic::on_unimplemented(
2346    message = "`{Self}` is not a signed integer SIMD vector",
2347    label = "not a signed integer vector",
2348    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."
2349)]
2350pub trait SignedIntegerVector: SignedVector + IntegerVector<Element: crate::element::SignedIntegerElement> {
2351    /// For each lane in the vector, right shift in sign bits by the immediate value.
2352    #[conditional] fn srai<const I: i32>(self) -> Self;
2353    /// For each lane in the vector, right shift in sign bits by the given value.
2354    #[conditional] fn sra(self, count: u32) -> Self;
2355    /// For each lane in the vector, right shift in sign bits by the corresponding lane in the shifts vector.
2356    #[conditional] fn srav(self, counts: Self::Unsigned) -> Self;
2357
2358    /// Floor average: `(a + b) >> 1` rounded toward -∞, computed without overflow.
2359    #[conditional] fn avg_floor(self, other: Self) -> Self;
2360    /// Ceiling average: `(a + b + 1) >> 1` rounded toward +∞, computed without overflow.
2361    #[conditional] fn avg_ceil(self, other: Self) -> Self;
2362
2363    /// Rounded high-half signed multiply: the fixed-point `Q(W-1)` product
2364    /// `(self * other + 2^(W-2)) >> (W-1)`, where `W` is the element bit width.
2365    ///
2366    /// For `i16` this is the Q15 rounded multiply (x86 `PMULHRSW`), the
2367    /// fixed-point DSP primitive for gain/volume, fades, and window functions.
2368    /// Unlike [`mulhi`](IntegerVector::mulhi) it rounds to nearest instead of
2369    /// truncating, avoiding a DC bias.
2370    #[conditional] fn mulhrs(self, other: Self) -> Self;
2371}
2372
2373/// The operations that read better on unsigned lanes: the power-of-two and
2374/// inclusive-range predicates, and the unsigned averages.
2375///
2376/// Implemented only by vectors of unsigned integer elements (`Vector<u32>`,
2377/// `u8xN`, ...). Several of these exist here specifically because the unsigned
2378/// form is cheaper: [`in_range`](Self::in_range) is one wrapping subtract and
2379/// one compare, against the two compares an explicit `lo <= x && x <= hi` costs.
2380#[rustfmt::skip] #[thermite_macros::vector_trait]
2381#[diagnostic::on_unimplemented(
2382    message = "`{Self}` is not an unsigned integer SIMD vector",
2383    label = "not an unsigned integer vector",
2384    note = "`UnsignedIntegerVector` is implemented only by vectors of unsigned integer elements (`Vector<u32>`, `u8xN`, ...). Signed integer and float vectors do not qualify."
2385)]
2386pub trait UnsignedIntegerVector: IntegerVector<Element: crate::element::UnsignedIntegerElement> {
2387    /// Determines if each unsigned integer element in the vector is a
2388    /// power of two, returning a mask indicating whether or not it is.
2389    fn is_power_of_two(self) -> Self::Mask;
2390
2391    /// Per-lane inclusive unsigned range test: a mask of `lo <= self <= hi`,
2392    /// assuming `lo <= hi`.
2393    ///
2394    /// Computed branchlessly as `(self - lo) <= (hi - lo)` with wrapping
2395    /// subtraction: a single unsigned compare instead of the two an explicit
2396    /// `self >= lo & self <= hi` would need. The workhorse of byte
2397    /// classification - testing digit/alpha/whitespace ranges.
2398    fn in_range(self, lo: Self, hi: Self) -> Self::Mask;
2399
2400    /// Returns the next power of two minus one for each unsigned integer
2401    /// element in the vector.
2402    #[conditional] fn next_power_of_two_m1(self) -> Self;
2403    /// Computes log2(x) + 1 for each unsigned integer element in the vector.
2404    #[conditional] fn ilog2p1(self) -> Self;
2405
2406    /// Compute the parity of each unsigned integer lane in the vector.
2407    #[conditional] fn parity(self) -> Self;
2408
2409    /// Ceiling average: `(a + b + 1) >> 1`, computed without overflow.
2410    ///
2411    /// Matches x86 `PAVGB`/`PAVGW` and ARM `vrhadd` semantics.
2412    #[conditional] fn avg(self, other: Self) -> Self;
2413
2414    /// Per-lane unsigned absolute difference `|self - other|`, without overflow.
2415    ///
2416    /// Computed branchlessly as `(self -| other) | (other -| self)` with
2417    /// saturating subtraction. The per-lane building block of sum-of-absolute-
2418    /// differences (block matching, motion estimation).
2419    #[conditional] fn abs_diff(self, other: Self) -> Self;
2420
2421    /// Per-lane `N`-dimensional Morton code (Z-order curve index): interleave the
2422    /// low `floor(W / N)` bits of each of the `N` coordinate vectors into one,
2423    /// placing bit `i` of `values[d]` at output position `i * N + d`. `N = 2` is
2424    /// the classic 2D code, `N = 3` the 3D (voxel/octree) code.
2425    ///
2426    /// The workhorse for spatial sorting (BVH/octree builds, grid binning,
2427    /// nearest-neighbour broad-phase): compute a whole vector of codes at once,
2428    /// then sort. [`reverse_morton`](Self::reverse_morton) inverts it.
2429    fn morton<const N: usize>(values: [Self; N]) -> Self;
2430
2431    /// Inverse of [`morton`](Self::morton): de-interleave a Morton code back into
2432    /// its `N` coordinate vectors, where `out[d]` gathers output bits
2433    /// `d, d + N, d + 2N, ...` into the low `floor(W / N)` bits.
2434    fn reverse_morton<const N: usize>(self) -> [Self; N];
2435}
2436
2437/// Escape hatch tying a [`Vector`] to its specific underlying
2438/// [`Register`](crate::register::Register) type.
2439///
2440/// Provides round-trip conversion between the user-facing [`Vector`] and the
2441/// raw register storage. Most generic code should bound on
2442/// [`GenericVector`] (or a more specific vector trait) and never need this;
2443/// it exists so that code which deliberately specializes on a particular
2444/// backend can drop down to the register layer without losing the trait
2445/// hierarchy on the way back up.
2446pub trait VectorWithRegister<R: crate::register::Register>: GenericVector {
2447    /// Consume the vector and yield its raw register storage.
2448    fn into_register(self) -> crate::register::Storage<R>;
2449
2450    /// Wrap a raw register storage value back into a `Vector`.
2451    fn from_register(reg: crate::register::Storage<R>) -> Self;
2452
2453    /// Borrow the vector's elements as a slice.
2454    ///
2455    /// The lane count travels as the slice length (always
2456    /// [`lanes()`](GenericVector::lanes)) rather than in the type, so this is the
2457    /// preferred read accessor over array-typed borrows.
2458    fn as_slice(&self) -> &[Self::Element];
2459
2460    /// Mutably borrow the vector's elements as a slice.
2461    ///
2462    /// See [`as_slice`](Self::as_slice).
2463    fn as_mut_slice(&mut self) -> &mut [Self::Element];
2464}
2465
2466/// Float vector types which have an associated hardware register type.
2467pub trait FloatVectorWithRegister:
2468    FloatVectorWithBits<Mask = crate::Mask<Self::Register>> + VectorWithRegister<Self::Register>
2469{
2470    /// The backing hardware register this vector is a thin wrapper over.
2471    type Register: crate::register::FloatRegister<Element = Self::Element, Lanes = Self::Lanes>;
2472}
2473
2474/// SignedBits integer vector types which have an associated hardware register type.
2475pub trait SignedIntegerVectorWithRegister:
2476    SignedIntegerVector<Mask = crate::Mask<Self::Register>> + VectorWithRegister<Self::Register>
2477{
2478    /// The backing hardware register this vector is a thin wrapper over.
2479    type Register: crate::register::SignedIntegerRegister<Element = Self::Element, Lanes = Self::Lanes>;
2480}
2481
2482/// Unsigned integer vector types which have an associated hardware register type.
2483pub trait UnsignedIntegerVectorWithRegister:
2484    UnsignedIntegerVector<Mask = crate::Mask<Self::Register>> + VectorWithRegister<Self::Register>
2485{
2486    /// The backing hardware register this vector is a thin wrapper over.
2487    type Register: crate::register::UnsignedIntegerRegister<Element = Self::Element, Lanes = Self::Lanes>;
2488}
2489
2490/// Floating-point vectors: the bound most user code should be written against.
2491///
2492/// Carries the float arithmetic, rounding, the FMA family, the predicates
2493/// (`is_finite`, `is_nan`, ...) and the [`FloatConsts`] values, on top of
2494/// everything [`SignedVector`] provides. The policy math library
2495/// ([`CoreMath`](crate::math::CoreMath),
2496/// [`TranscendentalMath`](crate::math::TranscendentalMath) and the rest) attaches
2497/// to this bound, so `V: FloatVector + TranscendentalMath` is the usual signature
2498/// for a numeric kernel.
2499///
2500/// Implemented by the 1-lane `Vector<f32>` / `Vector<f64>`, the native-width
2501/// `f32xN` / `f64xN`, and the composite float types (`Dual`, `Complex`,
2502/// `Compensated`), which is what lets one generic function run as plain SIMD, as
2503/// autodiff, or in double-double precision without being edited.
2504///
2505/// Bare `f32` and `f64` do **not** implement it. Wrap the scalar first with
2506/// `Vector::<f32>::splat(x)`, or use [`ScalarMath`](crate::math::ScalarMath) for
2507/// one-off scalar math.
2508#[rustfmt::skip] #[thermite_macros::vector_trait]
2509#[diagnostic::on_unimplemented(
2510    message = "`{Self}` is not a floating-point SIMD vector",
2511    label = "not a float vector",
2512    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`).",
2513    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()`, ...).",
2514    note = "Integer vectors are not float vectors either; convert with `.to_float()` or a cast before calling float operations."
2515)]
2516pub trait FloatVector: SignedVector<Element: FloatElement>
2517    + FloatConsts
2518    + CastVector<Self::ExtendedPrecision>
2519    + ops::MulAddExtMasked<Self::Mask, Self, Self, Output = Self>
2520    + ops::MulAddAssignExtMasked<Self::Mask, Self, Self>
2521    + ops::AddSubExtMasked<Self::Mask, Output = Self>
2522{
2523    /// The value `0.5` represented in this vector type.
2524    const HALF: Self;
2525    /// The value `-0.0` represented in this vector type.
2526    const NEG_ZERO: Self;
2527    /// The value `infinity` represented in this vector type.
2528    const INFINITY: Self;
2529    /// The value `-infinity` represented in this vector type.
2530    const NEG_INFINITY: Self;
2531    /// The value `NaN` represented in this vector type.
2532    const NAN: Self;
2533    /// Hardware epsilon value in this vector type.
2534    const EPSILON: Self;
2535
2536    /// If available, an extended precision floating point vector type
2537    /// corresponding to this vector type. E.g., for `f32` vectors, this
2538    /// would be an `f64` vector type.
2539    ///
2540    /// If no such type exists, this will be the same as `Self`.
2541    type ExtendedPrecision: FloatVector<Lanes = Self::Lanes> + CastVector<Self>;
2542
2543    /// Check if each element in the vector is infinite, returning a mask.
2544    fn is_infinite(self) -> Self::Mask;
2545
2546    /// Check if each element in the vector is finite, returning a mask.
2547    fn is_finite(self) -> Self::Mask;
2548
2549    /// Check if each element in the vector is NaN, returning a mask.
2550    fn is_nan(self) -> Self::Mask;
2551
2552    /// Check if each element in the vector is zero or subnormal, returning a mask.
2553    fn is_zero_or_subnormal(self) -> Self::Mask;
2554
2555    /// Check if each element in the vector is normal, returning a mask.
2556    fn is_normal(self) -> Self::Mask;
2557
2558    /// Check if each element in the vector is subnormal, returning a mask.
2559    fn is_subnormal(self) -> Self::Mask;
2560
2561    /// `true` if the backend has a hardware approximate-reciprocal
2562    /// instruction (e.g. `rcpps` on x86). When `false`, [`rcp`](Self::rcp)
2563    /// falls back to a full IEEE division and provides no speed advantage
2564    /// over `Self::ONE / self`.
2565    const HAS_APPROX_RCP: bool;
2566
2567    /// `true` if the backend has a hardware approximate-reciprocal-square-root
2568    /// instruction (e.g. `rsqrtps` on x86). When `false`, [`rsqrt`](Self::rsqrt)
2569    /// falls back to `Self::ONE / self.sqrt()`.
2570    const HAS_APPROX_RSQRT: bool;
2571
2572    /// Lane-wise IEEE 754 square root.
2573    ///
2574    /// Negative inputs (other than `-0.0`) produce NaN. `sqrt(-0.0)` is `-0.0`.
2575    #[conditional] fn sqrt(self) -> Self;
2576
2577    /// Lane-wise approximate reciprocal square root.
2578    ///
2579    /// Accuracy is hardware-dependent (typically 12 bits on x86 `rsqrtps`,
2580    /// closer to full precision on newer ISAs). For full-precision results
2581    /// or backends without hardware support, see [`HAS_APPROX_RSQRT`](Self::HAS_APPROX_RSQRT).
2582    #[conditional] fn rsqrt(self) -> Self;
2583
2584    /// Lane-wise approximate reciprocal: `1 / self`.
2585    ///
2586    /// Accuracy is hardware-dependent (typically 12 bits on x86 `rcpps`).
2587    /// For full-precision results or backends without hardware support,
2588    /// see [`HAS_APPROX_RCP`](Self::HAS_APPROX_RCP), or use `Self::ONE / self`.
2589    #[conditional] fn rcp(self) -> Self;
2590
2591    /// Lane-wise floor: largest integer less than or equal to each element.
2592    ///
2593    /// Result type stays the same; the value is the integer rounded toward
2594    /// negative infinity, kept in the float representation.
2595    #[conditional] fn floor(self) -> Self;
2596
2597    /// Lane-wise ceiling: smallest integer greater than or equal to each
2598    /// element, kept in the float representation.
2599    #[conditional] fn ceil(self) -> Self;
2600
2601    /// Lane-wise round-to-nearest.
2602    ///
2603    /// Halfway cases follow the current rounding mode of the hardware. On
2604    /// x86 this is round-half-to-even (banker's rounding), which differs
2605    /// from the scalar `f32::round` / `f64::round` half-away-from-zero
2606    /// convention. If you need a specific tie-breaking rule, do it explicitly.
2607    #[conditional] fn round(self) -> Self;
2608
2609    /// Lane-wise truncation toward zero (drops the fractional part), kept
2610    /// in the float representation.
2611    #[conditional] fn trunc(self) -> Self;
2612
2613    /// Lane-wise fractional part: `self - self.trunc()`.
2614    ///
2615    /// Result has the same sign as the input. For very large magnitudes the
2616    /// fractional part is exactly zero because the float has no fractional bits.
2617    #[conditional] fn fract(self) -> Self;
2618
2619    /// Effectively `self * sign.signum()`, multiplying the sign bits.
2620    #[conditional] fn mul_sign(self, sign: Self) -> Self;
2621
2622    /// Returns zero with the sign of `self`, i.e.: only the sign bit is set.
2623    #[conditional] fn signed_zero(self) -> Self;
2624
2625    /// Returns the next representable value greater than the current value, towards positive infinity.
2626    #[conditional] fn next_up(self) -> Self;
2627
2628    /// Returns the next representable value less than the current value, towards negative infinity.
2629    #[conditional] fn next_down(self) -> Self;
2630
2631    /// Linearly interpolates between `a` and `b` by `self`, where `self` is typically in the range `[0, 1]`.
2632    ///
2633    /// Follows the formula: `a * (1 - self) + b * self`, but the underlying implementation
2634    /// may optimize into certain other formulations.
2635    fn mix(self, a: Self, b: Self) -> Self;
2636
2637    /// Computes `$1 - x^2$` accurately, avoiding the cancellation a naive `1 - self * self`
2638    /// suffers as `self` approaches `±1` (where the result is small but `self * self` is near 1).
2639    ///
2640    /// With hardware FMA this is `nmul_add(self, self, 1)`: the exact product `$x^2$` is formed
2641    /// and subtracted from one with a single rounding. Without FMA it falls back to the factored
2642    /// `$(1 - x)(1 + x)$`, also cancellation-free (`1 - self` is exact for `self` near 1 by
2643    /// Sterbenz's lemma). Both keep full relative accuracy in the small result.
2644    #[inline(always)]
2645    fn one_minus_sq(self) -> Self {
2646        if const { Self::HAS_TRUE_FMA } {
2647            // FMA: 1 - self*self formed from the exact product with a single rounding.
2648            self.nmul_add(self, Self::ONE)
2649        } else {
2650            // No FMA: factored difference of squares, cancellation-free near |self| = 1.
2651            (Self::ONE - self) * (Self::ONE + self)
2652        }
2653    }
2654
2655    /// Inhibit further LLVM auto-vectorization of code surrounding this call.
2656    ///
2657    /// LLVM sometimes tries to "vectorize the vectors" -- repacking
2658    /// already-SIMD code into a wider form that ends up slower. Inserting
2659    /// this call inside a hot loop blocks that pass at the use site. The
2660    /// call itself emits no instructions; only the optimizer barrier remains.
2661    ///
2662    /// # Safety
2663    ///
2664    /// Memory-safe to call, but the side effect on code generation is
2665    /// significant. Only reach for this when you have measured a regression
2666    /// caused by over-aggressive auto-vectorization.
2667    unsafe fn block_autovectorization(&mut self);
2668
2669    /// Attempt to upcast this FloatVector to a FloatVectorWithBits,
2670    /// using the provided kernel. If not possible, returns None.
2671    fn with_bits<const N: usize, K: AsFloatVectorWithBitsKernel<Self, N>>(
2672        _values: [Self; N],
2673        _kernel: K,
2674    ) -> Option<<K as AsFloatVectorWithBitsKernel<Self, N>>::Output> {
2675        None // Default implementation returns None
2676    }
2677}
2678
2679/// Inclusive scan ladder at the **vector** layer, for composite vector types.
2680///
2681/// The register-layer ladder in
2682/// [`polyfills::scan`](crate::backend::generic::polyfills::scan) is written in
2683/// `Register` ops and so cannot be reused by `Dual`/`Compensated`/`Complex`, whose
2684/// scans have to run on their own `Self` operations (a dual carries the winning
2685/// lane's derivative; a compensated sum has to renormalise its error term). This is
2686/// the same ladder spelled in [`GenericVector`] methods, exported so those crates
2687/// share one copy.
2688///
2689/// Invoke inside an `impl` block for the composite -- it resolves `Self`:
2690///
2691/// ```ignore
2692/// fn prefix_min(self) -> Self {
2693///     thermite::scan_ladder!(forward, self, self.broadcast::<0>(), Self::min)
2694/// }
2695/// fn reverse_prefix_sum(self) -> Self {
2696///     thermite::scan_ladder!(reverse, self, Self::ZERO, core::ops::Add::add)
2697/// }
2698/// ```
2699///
2700/// `$op` must be associative (a doubling ladder reassociates freely), and `$fill`
2701/// must leave the already-final lanes alone: `ZERO` for a sum, and a broadcast of
2702/// the *edge* lane for `min`/`max` -- lane 0 forward, lane `LANES - 1` reverse.
2703/// `MIN`/`MAX` are finite bounds and would clamp an infinite lane, which is the same
2704/// trap the register ladder documents.
2705///
2706/// `align`'s offset is a const-generic argument and must be a literal. The reverse
2707/// direction is fine (the shift *is* the offset), but the forward direction needs
2708/// `LANES - s`, hence the match on the compile-time lane count with a per-width
2709/// offset list -- exactly one arm survives monomorphization. Widths outside
2710/// power-of-two `<= 64` have no arm and fall back to reversing, running the reverse
2711/// ladder, and reversing back, which needs only literal shifts and is correct at any
2712/// width.
2713///
2714/// Every stage is an `align`, so on a vector whose
2715/// [`HAS_NATIVE_ALIGN`](GenericVector::HAS_NATIVE_ALIGN) is false each one expands to
2716/// a shuffle-and-blend and the ladder gets correspondingly more expensive. It is
2717/// still `ceil(log2(LANES))` stages against a per-lane walk's `LANES` extract/insert
2718/// pairs, which is why this does not switch lowering the way the register-layer
2719/// ladder does -- there the fallback walks a slice in place and is genuinely cheaper.
2720/// Gate on the const at the call site if a specific composite says otherwise.
2721#[doc(hidden)]
2722#[macro_export]
2723macro_rules! scan_ladder {
2724    (reverse, $v:expr, $fill:expr, $op:path) => {{
2725        let mut v = $v;
2726        let f = $fill;
2727        #[rustfmt::skip]
2728        let () = {
2729            if const { Self::LANES >  1 } { v = $op(v, v.align::<1>(f)); }
2730            if const { Self::LANES >  2 } { v = $op(v, v.align::<2>(f)); }
2731            if const { Self::LANES >  4 } { v = $op(v, v.align::<4>(f)); }
2732            if const { Self::LANES >  8 } { v = $op(v, v.align::<8>(f)); }
2733            if const { Self::LANES > 16 } { v = $op(v, v.align::<16>(f)); }
2734            if const { Self::LANES > 32 } { v = $op(v, v.align::<32>(f)); }
2735                        };
2736        v
2737    }};
2738
2739    (forward, $v:expr, $fill:expr, $op:path) => {{
2740        let mut v = $v;
2741        let f = $fill;
2742
2743        if const { Self::LANES.is_power_of_two() && Self::LANES <= 64 } {
2744            // `a.align::<OFFSET>(b)[i] == concat(a, b)[OFFSET + i]`, so with `a = fill`
2745            // and `b = v` the stage that wants `v[i - s]` is `OFFSET == LANES - s`.
2746            #[rustfmt::skip]
2747            let () = match const { Self::LANES } {
2748                0 | 1 => {}
2749                2  => { v = $op(v, f.align::<1>(v)); }
2750                4  => { v = $op(v, f.align::<3>(v));
2751                        v = $op(v, f.align::<2>(v)); }
2752                8  => { v = $op(v, f.align::<7>(v));
2753                        v = $op(v, f.align::<6>(v));
2754                        v = $op(v, f.align::<4>(v)); }
2755                16 => { v = $op(v, f.align::<15>(v));
2756                        v = $op(v, f.align::<14>(v));
2757                        v = $op(v, f.align::<12>(v));
2758                        v = $op(v, f.align::<8>(v)); }
2759                32 => { v = $op(v, f.align::<31>(v));
2760                        v = $op(v, f.align::<30>(v));
2761                        v = $op(v, f.align::<28>(v));
2762                        v = $op(v, f.align::<24>(v));
2763                        v = $op(v, f.align::<16>(v)); }
2764                64 => { v = $op(v, f.align::<63>(v));
2765                        v = $op(v, f.align::<62>(v));
2766                        v = $op(v, f.align::<60>(v));
2767                        v = $op(v, f.align::<56>(v));
2768                        v = $op(v, f.align::<48>(v));
2769                                        v = $op(v, f.align::<32>(v)); }
2770                                // unreachable: guarded by the `if const` above. Panicking is the right
2771                                // failure mode if a width ever slips past that guard.
2772                                _ => unreachable!(),
2773                            };
2774            v
2775        } else {
2776            // `fill` is the lane-0 broadcast either way: reversing makes it the last
2777            // lane, which is exactly what the reverse ladder wants.
2778            $crate::scan_ladder!(reverse, v.reverse(), f, $op).reverse()
2779        }
2780    }};
2781}
2782
2783/// Run a closure-like block with a generic [`FloatVector`] temporarily upcast
2784/// to a [`FloatVectorWithBits`], when the backend supports it.
2785///
2786/// Given an array of `FloatVector` values and a body parameterized over a
2787/// `FloatVectorWithBits` type, this expands to a call to
2788/// [`FloatVector::with_bits`] with an anonymous kernel implementing
2789/// [`AsFloatVectorWithBitsKernel`]. The body only runs when bit access is
2790/// available for the concrete backend; otherwise the whole expression evaluates
2791/// to `None` (the return type is therefore `Option<_>`).
2792///
2793/// This is the ergonomic front-end to the [`AsFloatVectorWithBitsKernel`]
2794/// pattern; reach for it inside generic code bounded only on `FloatVector` that
2795/// wants an optional fast path requiring bit-level access.
2796#[macro_export]
2797macro_rules! with_bits {
2798    // (($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)* }) => {{
2799    //     $crate::with_bits!(($first_value): $ty as fn($first_decl: $first_alias) -> impl $ret $(where $($c: $constraint),*)? {
2800    //         $crate::with_bits!(($($value),+): $ty as fn($($decl: $alias),*) -> $ret $(where $($c: $constraint),*)? {
2801    //             $($body)*
2802    //         })
2803    //     })
2804    // }};
2805
2806    ([$($values:expr),+]: [$ty:ty; $len:literal] as fn($decl:ident: [$alias:ident; _]) -> $ret:ty $(where $($c:ty: $constraint:ident),*)? { $($body:tt)* }) => {{
2807        struct AnonymousAsFloatVectorWithBitsKernel<V>(core::marker::PhantomData<V>);
2808
2809        impl<V: FloatVector> $crate::vector::AsFloatVectorWithBitsKernel<V, $len> for AnonymousAsFloatVectorWithBitsKernel<V>
2810            $(where $($c: $constraint),*)?
2811        {
2812            type Output = $ret;
2813
2814            fn with_bits<
2815                $alias: FloatVectorWithBits<
2816                        Element = V::Element,
2817                        Lanes = V::Lanes,
2818                        Mask = V::Mask,
2819                        Signed = V::Signed,
2820                        Unsigned = V::Unsigned,
2821                        ExtendedPrecision = V::ExtendedPrecision,
2822                    > + CastVector<V>,
2823            >(
2824                self,
2825                $decl: [$alias; $len],
2826            ) -> Self::Output {
2827                $($body)*
2828            }
2829        }
2830
2831        <V as FloatVector>::with_bits(
2832            [$($values),+],
2833            AnonymousAsFloatVectorWithBitsKernel::<V>(core::marker::PhantomData),
2834        )
2835    }};
2836}
2837
2838/// Some algorithms may benefit from being able to access the bitwise
2839/// representation of floating point vectors. However, not all vectors
2840/// support this functionality, and those that do may be passed as generic
2841/// FloatVector. Therefore, this is a way of upcasting a FloatVector
2842/// to a FloatVectorWithBits, if possible. If not possible, returns None.
2843pub trait AsFloatVectorWithBitsKernel<O: FloatVector, const N: usize> {
2844    /// Whatever the kernel body returns, threaded back out through the upcast.
2845    type Output;
2846
2847    /// Runs the kernel with `v` re-typed as a [`FloatVectorWithBits`].
2848    ///
2849    /// The bound is written on the method rather than the trait so the caller
2850    /// stays generic over plain [`FloatVector`]. The bit-level type only exists
2851    /// inside this call.
2852    fn with_bits<
2853        V: FloatVectorWithBits<
2854                Element = O::Element,
2855                Lanes = O::Lanes,
2856                Mask = O::Mask,
2857                Signed = O::Signed,
2858                Unsigned = O::Unsigned,
2859                ExtendedPrecision = O::ExtendedPrecision,
2860            > + CastVector<O>,
2861    >(
2862        self,
2863        v: [V; N],
2864    ) -> Self::Output;
2865}
2866
2867/// A [`FloatVector`] that additionally exposes its raw bit representation as
2868/// companion integer vectors, enabling bit-level float algorithms.
2869///
2870/// On top of [`FloatVector`] this provides:
2871/// - the [`Bits`](Self::Bits) (unsigned) and [`SignedBits`](Self::SignedBits)
2872///   integer vector types matching this float's bit width and lane count, with
2873///   full [`FullyInteroperable`] cast/bitcast interop between all three views;
2874/// - hardware-accelerated `native_*` transcendentals gated by
2875///   [`NATIVE_CAP`](Self::NATIVE_CAP);
2876/// - bit-level helpers like [`total_order`](Self::total_order) /
2877///   [`linear_order`](Self::linear_order) for sorting and ULP math.
2878///
2879/// Not every float vector implements this (it requires the element to be a
2880/// [`FloatElementWithBits`]); generic code that only sometimes needs bit access
2881/// can attempt to obtain it via [`FloatVector::with_bits`].
2882///
2883/// The methods on this trait do **not** have masked (`_c`/`_m`/`_z`) variants.
2884#[diagnostic::on_unimplemented(
2885    message = "`{Self}` does not expose float bit-manipulation operations",
2886    label = "no `ldexp` / `frexp` or raw bit access",
2887    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."
2888)]
2889pub trait FloatVectorWithBits:
2890    BitwiseVector
2891    + FloatVector<Element: FloatElementWithBits, Signed: CastVector<Self::SignedBits>, Unsigned: CastVector<Self::Bits>>
2892    + GenericVector<
2893        Signed: GenericVector<Mask: CastMask<<Self::SignedBits as GenericVector>::Mask>>,
2894        Unsigned: GenericVector<Mask: CastMask<<Self::Unsigned as GenericVector>::Mask>>,
2895    > + FullyInteroperable<Self::Bits, Self::SignedBits>
2896{
2897    /// This vector's bit pattern viewed as *signed* integer lanes of the same
2898    /// width, for exponent arithmetic and the sign-aware bit tricks.
2899    type SignedBits: SignedIntegerVector<
2900            Mask: CastMask<<Self::Signed as GenericVector>::Mask>,
2901            Lanes = Self::Lanes,
2902            Divider = Divider<<Self::Element as FloatElementWithBits>::SignedBits>,
2903            BranchfreeDivider = BranchfreeDivider<<Self::Element as FloatElementWithBits>::SignedBits>,
2904            Element = <Self::Element as FloatElementWithBits>::SignedBits,
2905        > + FullyInteroperable<Self, Self::Bits>
2906        + CastVector<Self::Signed>;
2907
2908    /// This vector's bit pattern viewed as *unsigned* integer lanes of the same
2909    /// width, which is what masking and shifting the raw bits wants.
2910    type Bits: UnsignedIntegerVector<
2911            Mask: CastMask<<Self::Unsigned as GenericVector>::Mask>,
2912            Lanes = Self::Lanes,
2913            Divider = Divider<<Self::Element as FloatElementWithBits>::Bits>,
2914            BranchfreeDivider = BranchfreeDivider<<Self::Element as FloatElementWithBits>::Bits>,
2915            Element = <Self::Element as FloatElementWithBits>::Bits,
2916        > + FullyInteroperable<Self, Self::SignedBits>
2917        + CastVector<Self::Unsigned>;
2918
2919    /// Bit-flag set describing which `native_*` methods on this trait have a
2920    /// real hardware implementation on the current backend.
2921    ///
2922    /// Test with `NATIVE_CAP.has(NativeCapability::SIN)` etc. before calling
2923    /// the corresponding `native_*` method directly; otherwise the default
2924    /// implementation will panic.
2925    const NATIVE_CAP: NativeCapability;
2926
2927    /// Hardware-accelerated `ldexp`: `self * 2^exp`, lane-wise.
2928    ///
2929    /// # Safety
2930    /// Only callable when [`NATIVE_CAP`](Self::NATIVE_CAP) advertises `LDEXP`.
2931    /// Calling on a backend without hardware support is undefined behavior
2932    /// (the default impl panics via `unreachable!` at the register layer).
2933    unsafe fn native_ldexp(self, exp: Self::SignedBits) -> Self;
2934
2935    /// Hardware-accelerated `frexp`: split each lane into a normalized
2936    /// mantissa in `[0.5, 1.0)` and an integer exponent.
2937    ///
2938    /// # Safety
2939    /// Only callable when [`NATIVE_CAP`](Self::NATIVE_CAP) advertises `FREXP`.
2940    unsafe fn native_frexp(self) -> (Self, Self::SignedBits);
2941
2942    /// Hardware-accelerated combined sine and cosine, lane-wise.
2943    ///
2944    /// # Safety
2945    /// Only callable when [`NATIVE_CAP`](Self::NATIVE_CAP) advertises `SIN_COS`.
2946    unsafe fn native_sin_cos<P: Policy>(self) -> (Self, Self);
2947
2948    /// Hardware-accelerated sine, lane-wise.
2949    ///
2950    /// # Safety
2951    /// Only callable when [`NATIVE_CAP`](Self::NATIVE_CAP) advertises `SIN`.
2952    unsafe fn native_sin<P: Policy>(self) -> Self;
2953
2954    /// Hardware-accelerated cosine, lane-wise.
2955    ///
2956    /// # Safety
2957    /// Only callable when [`NATIVE_CAP`](Self::NATIVE_CAP) advertises `COS`.
2958    unsafe fn native_cos<P: Policy>(self) -> Self;
2959
2960    /// Hardware-accelerated tangent, lane-wise.
2961    ///
2962    /// # Safety
2963    /// Only callable when [`NATIVE_CAP`](Self::NATIVE_CAP) advertises `TAN`.
2964    unsafe fn native_tan<P: Policy>(self) -> Self;
2965
2966    /// Hardware-accelerated `2^self`, lane-wise.
2967    ///
2968    /// # Safety
2969    /// Only callable when [`NATIVE_CAP`](Self::NATIVE_CAP) advertises `EXP2`.
2970    unsafe fn native_exp2<P: Policy>(self) -> Self;
2971
2972    /// Hardware-accelerated `log2(self)`, lane-wise.
2973    ///
2974    /// # Safety
2975    /// Only callable when [`NATIVE_CAP`](Self::NATIVE_CAP) advertises `LOG2`.
2976    unsafe fn native_log2<P: Policy>(self) -> Self;
2977
2978    /// Hardware-accelerated `e^self`, lane-wise.
2979    ///
2980    /// # Safety
2981    /// Only callable when [`NATIVE_CAP`](Self::NATIVE_CAP) advertises `EXP`.
2982    unsafe fn native_exp<P: Policy>(self) -> Self;
2983
2984    /// Hardware-accelerated natural logarithm, lane-wise.
2985    ///
2986    /// # Safety
2987    /// Only callable when [`NATIVE_CAP`](Self::NATIVE_CAP) advertises `LN`.
2988    unsafe fn native_ln<P: Policy>(self) -> Self;
2989
2990    /// Hardware-accelerated `self^exp`, lane-wise.
2991    ///
2992    /// # Safety
2993    /// Only callable when [`NATIVE_CAP`](Self::NATIVE_CAP) advertises `POWF`.
2994    unsafe fn native_powf<P: Policy>(self, exp: Self) -> Self;
2995
2996    /// Return a signed integer vector that is capable of encapsulating
2997    /// the "total order" of the floating point values in this vector,
2998    /// such that when compared as integers, the ordering is the same
2999    /// as the floating point ordering, including NaNs, in the following order:
3000    ///
3001    /// - negative quiet NaN
3002    /// - negative signaling NaN
3003    /// - negative infinity
3004    /// - negative numbers
3005    /// - negative subnormal numbers
3006    /// - negative zero
3007    /// - positive zero
3008    /// - positive subnormal numbers
3009    /// - positive numbers
3010    /// - positive infinity
3011    /// - positive signaling NaN
3012    /// - positive quiet NaN.
3013    ///
3014    /// This is useful for sorting floating point numbers in a way that
3015    /// is consistent and well-defined. However, it may differ from
3016    /// the default floating point comparison behavior of the platform.
3017    ///
3018    /// # Example
3019    /// ```rust
3020    /// # use thermite::backend::scalar::prelude::*;
3021    /// let x = f32x4::NAN;
3022    /// let y = f32x4::ONE;
3023    /// let total_lt = x.total_order().cmp_lt(y.total_order());
3024    /// assert!(total_lt.none()); // NaN is not less than 1.0 in total order
3025    /// ```
3026    fn total_order(self) -> Self::SignedBits;
3027
3028    /// Similar to [`total_order`](FloatVectorWithBits::total_order), but positive zero and negative zero are
3029    /// the same value. This can be used for calculating ULP differences by simply subtracting one from another.
3030    fn linear_order(self) -> Self::SignedBits;
3031}
3032
3033/// Convenience accessors `x()` / `y()` automatically available on any
3034/// 2-lane [`GenericVector`].
3035///
3036/// Each method is just shorthand for [`extract`](GenericVector::extract) at
3037/// the corresponding compile-time index.
3038#[rustfmt::skip]
3039pub trait GenericVector2: GenericVector {
3040    /// Returns the value of lane 0.
3041    #[inline(always)] fn x(&self) -> Self::Element { self.extract::<0>() }
3042    /// Returns the value of lane 1.
3043    #[inline(always)] fn y(&self) -> Self::Element { self.extract::<1>() }
3044}
3045
3046/// Convenience accessors `x()` / `y()` / `z()` automatically available on any
3047/// 3-lane [`GenericVector`].
3048///
3049/// Each method is just shorthand for [`extract`](GenericVector::extract) at
3050/// the corresponding compile-time index.
3051#[rustfmt::skip]
3052pub trait GenericVector3: GenericVector {
3053    /// Returns the value of lane 0.
3054    #[inline(always)] fn x(&self) -> Self::Element { self.extract::<0>() }
3055    /// Returns the value of lane 1.
3056    #[inline(always)] fn y(&self) -> Self::Element { self.extract::<1>() }
3057    /// Returns the value of lane 2.
3058    #[inline(always)] fn z(&self) -> Self::Element { self.extract::<2>() }
3059}
3060
3061/// Convenience accessors `x()` / `y()` / `z()` / `w()` automatically available
3062/// on any 4-lane [`GenericVector`].
3063///
3064/// Each method is just shorthand for [`extract`](GenericVector::extract) at
3065/// the corresponding compile-time index.
3066#[rustfmt::skip]
3067pub trait GenericVector4: GenericVector {
3068    /// Returns the value of lane 0.
3069    #[inline(always)] fn x(&self) -> Self::Element { self.extract::<0>() }
3070    /// Returns the value of lane 1.
3071    #[inline(always)] fn y(&self) -> Self::Element { self.extract::<1>() }
3072    /// Returns the value of lane 2.
3073    #[inline(always)] fn z(&self) -> Self::Element { self.extract::<2>() }
3074    /// Returns the value of lane 3.
3075    #[inline(always)] fn w(&self) -> Self::Element { self.extract::<3>() }
3076}
3077
3078impl<V: GenericVector<Lanes = typenum::U2>> GenericVector2 for V {}
3079impl<V: GenericVector<Lanes = typenum::U3>> GenericVector3 for V {}
3080impl<V: GenericVector<Lanes = typenum::U4>> GenericVector4 for V {}
3081
3082#[rustfmt::skip]
3083macro_rules! impl_swizzle4 {
3084    (@ x) => { 0 };
3085    (@ y) => { 1 };
3086    (@ z) => { 2 };
3087    (@ w) => { 3 };
3088
3089    (IMPL x x x x) => { #[inline(always)] fn xxxx(self) -> Self { self.broadcast::<0>() } };
3090    (IMPL y y y y) => { #[inline(always)] fn yyyy(self) -> Self { self.broadcast::<1>() } };
3091    (IMPL z z z z) => { #[inline(always)] fn zzzz(self) -> Self { self.broadcast::<2>() } };
3092    (IMPL w w w w) => { #[inline(always)] fn wwww(self) -> Self { self.broadcast::<3>() } };
3093
3094    (IMPL $a:ident $b:ident $c:ident $d:ident) => {paste::paste! {
3095        #[inline(always)]
3096        fn [<$a $b $c $d>](self) -> Self {
3097            struct Indices;
3098
3099            impl crate::swizzle::SwizzleIndices<typenum::U4> for Indices {
3100                const INDICES: GenericArray<u32, typenum::U4> = {
3101                    unsafe { $crate::generic_array::const_transmute::<_, GenericArray<u32, typenum::U4>>([
3102                        impl_swizzle4!(@ $a),
3103                        impl_swizzle4!(@ $b),
3104                        impl_swizzle4!(@ $c),
3105                        impl_swizzle4!(@ $d)
3106                    ]) }
3107                };
3108            }
3109
3110            self.permute_const::<Indices>()
3111        }
3112    }};
3113
3114    (DECL $(#[$meta:meta])* $a:ident $b:ident $c:ident $d:ident) => {paste::paste! {
3115        #[allow(missing_docs)]
3116        $(#[$meta])* fn [<$a $b $c $d>](self) -> Self;
3117    }};
3118
3119    ($( $(#[$meta:meta])* [$a:ident $b:ident $c:ident $d:ident]),*) => {
3120        /// Only available for 4-lane vectors, this allows human-readable swizzle/permutations
3121        /// of the vector.
3122        pub trait Swizzle4: SwizzleVector<Lanes = typenum::U4> { $(impl_swizzle4!(DECL $(#[$meta])* $a $b $c $d);)* }
3123
3124        /// Implements 4-lane swizzling for vectors.
3125        impl<V: SwizzleVector<Lanes = typenum::U4>> Swizzle4 for V {
3126            $(impl_swizzle4!(IMPL $a $b $c $d);)*
3127        }
3128    }
3129}
3130
3131#[rustfmt::skip]
3132macro_rules! impl_swizzle3 {
3133    (IMPL x x x) => { #[inline(always)] fn xxx(self) -> Self { self.broadcast::<0>() } };
3134    (IMPL y y y) => { #[inline(always)] fn yyy(self) -> Self { self.broadcast::<1>() } };
3135    (IMPL z z z) => { #[inline(always)] fn zzz(self) -> Self { self.broadcast::<2>() } };
3136
3137    (IMPL $a:ident $b:ident $c:ident) => {paste::paste! {
3138        #[inline(always)]
3139        fn [<$a $b $c>](self) -> Self {
3140            struct Indices;
3141
3142            impl crate::swizzle::SwizzleIndices<typenum::U3> for Indices {
3143                const INDICES: GenericArray<u32, typenum::U3> = {
3144                    unsafe { $crate::generic_array::const_transmute::<_, GenericArray<u32, typenum::U3>>([
3145                        impl_swizzle4!(@ $a),
3146                        impl_swizzle4!(@ $b),
3147                        impl_swizzle4!(@ $c)
3148                    ]) }
3149                };
3150            }
3151
3152            self.permute_const::<Indices>()
3153        }
3154    }};
3155
3156    (DECL $(#[$meta:meta])* $a:ident $b:ident $c:ident) => {paste::paste! {
3157        #[allow(missing_docs)]
3158        $(#[$meta])* fn [<$a $b $c>](self) -> Self;
3159    }};
3160
3161    ($( $(#[$meta:meta])* [$a:ident $b:ident $c:ident]),*) => {
3162        /// Only available for "3-lane" (ignoring 4th lane) [`LinAlg3Register`](crate::register::LinAlg3Register) vectors,
3163        /// this allows human-readable swizzle/permutations of the vector. Permutations
3164        /// will ignore the 4th lane of the register, leaving it unchanged.
3165        pub trait Swizzle3: SwizzleVector<Lanes = typenum::U3> { $(impl_swizzle3!(DECL $(#[$meta])* $a $b $c);)* }
3166
3167        /// Implements 3-lane swizzling for vectors support 3-lane linear algebra operations.
3168        impl<V: SwizzleVector<Lanes = typenum::U3>> Swizzle3 for V {
3169            $(impl_swizzle3!(IMPL $a $b $c);)*
3170        }
3171    }
3172}
3173
3174impl_swizzle3! {
3175    [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],
3176    [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],
3177    [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]
3178}
3179
3180impl_swizzle4! {
3181    [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],
3182    [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],
3183    [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],
3184    [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],
3185    [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],
3186    [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],
3187    [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],
3188    [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],
3189    [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],
3190    [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],
3191    [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],
3192    [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],
3193    [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],
3194    [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],
3195    [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],
3196    [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],
3197    [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],
3198    [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],
3199    [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],
3200    [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],
3201    [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],
3202    [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],
3203    [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],
3204    [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],
3205    [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],
3206    [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],
3207    [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],
3208    [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],
3209    [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],
3210    [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],
3211    [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],
3212    [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]
3213}
3214
3215/// Vector suitable for 3D linear algebra operations.
3216///
3217/// The length of this vector must be either 3 or 4 lanes.
3218///
3219/// Methods in this are specifically optimized to either ignore the fourth lane (if it exists),
3220/// or to use algorithms that map especially well when there are truly only three "lanes",
3221/// such as on GPUs.
3222pub trait LinAlg3Vector: FloatVector {
3223    /// Scalar Product using only the first three lanes of the register as a 3D vector.
3224    ///
3225    /// This is more efficient than a raw scalar product, as there is no need to
3226    /// zero out the last lane of the register.
3227    fn dot3(self, other: Self) -> Self::Element;
3228
3229    /// Cross Product using only the first three lanes of the register as a 3D vector.
3230    ///
3231    /// This is more efficient than a raw cross product, as there is no need to
3232    /// zero out the last lane of the register.
3233    ///
3234    /// The `DOP` generic parameter indicates whether to use the
3235    /// "Difference of Products" method for computing the cross product,
3236    /// which can be more accurate in some cases, but _requires_
3237    /// hardware fused multiply-add instructions to be efficient.
3238    ///
3239    /// If you want the best performance, set `DOP` to `false`.\
3240    /// If you want the best accuracy or have FMA support, set `DOP` to `true`.
3241    fn cross3<const DOP: bool>(self, other: Self) -> Self;
3242
3243    /// Refraction of incident vector `self` through a surface with normal `n`
3244    /// and relative index of refraction `eta` (`$\eta = \eta_i/\eta_t$`). `self` and `n` are
3245    /// assumed unit length.
3246    ///
3247    /// Total internal reflection (`1 - eta^2*(1 - dot(n,self)^2) < 0`) returns the
3248    /// zero vector; otherwise `eta*self - (eta*dot(n,self) + sqrt(k))*n`
3249    fn refract(self, n: Self, eta: Self::Element) -> Self;
3250
3251    /// Efficiently set the 4th (last) lane of the register to 0.0.
3252    ///
3253    /// Useful for sanitizing 3D Homogeneous vectors.
3254    ///
3255    /// See [`LinAlg3Vector::one4`] for similar functionality for 3D points.
3256    fn zero4(self) -> Self;
3257
3258    /// Efficiently set the 4th (last) lane of the register to 1.0.
3259    ///
3260    /// Useful for sanitizing 3D Homogeneous points.
3261    ///
3262    /// See [`LinAlg3Vector::zero4`] for similar functionality for 3D vectors.
3263    fn one4(self) -> Self;
3264
3265    /// Returns the minimum value in the first three lanes of the register.
3266    fn min_element3(self) -> Self::Element;
3267
3268    /// Returns the maximum value in the first three lanes of the register.
3269    fn max_element3(self) -> Self::Element;
3270
3271    /// Returns the sum of the first three elements of the register.
3272    fn sum_elements3(self) -> Self::Element;
3273
3274    /// Returns the product of the first three elements of the register.
3275    fn prod_elements3(self) -> Self::Element;
3276
3277    /// 3x3 Matrix Transpose.
3278    ///
3279    /// Only the first three lanes of each output column are meaningful; the 4th
3280    /// lane (on 4-lane vectors) is unspecified.
3281    fn mat3_transpose(m: &[Self; 3]) -> [Self; 3];
3282
3283    /// 3x3 Matrix-Vector multiplication, assuming `self` as the vector.
3284    fn mat3_vec3_product<const COLUMN_MAJOR: bool>(self, m: &[Self; 3]) -> Self;
3285
3286    /// 3x3 matrix times `N` 3D vectors (small-`N` batch; see
3287    /// [`mat4_vec4_product_array`](LinAlg4Vector::mat4_vec4_product_array)).
3288    fn mat3_vec3_product_array<const COLUMN_MAJOR: bool, const N: usize>(
3289        m: &[Self; 3],
3290        vectors: &[Self; N],
3291    ) -> [Self; N];
3292
3293    /// 3x3 Matrix-Matrix multiplication.
3294    ///
3295    /// If `COLUMN_MAJOR` is `false`, the matrices are treated as row-major and
3296    /// the multiplication order becomes `rhs * lhs`, mirroring
3297    /// [`mat4_product`](LinAlg4Vector::mat4_product).
3298    fn mat3_product<const COLUMN_MAJOR: bool>(lhs: &[Self; 3], rhs: &[Self; 3]) -> [Self; 3];
3299
3300    /// Determinant of a column-major 3x3 matrix.
3301    fn mat3_det(m: &[Self; 3]) -> Self::Element;
3302
3303    /// In-place 3x3 Matrix inversion; **returns the determinant**.
3304    ///
3305    /// An exactly-zero determinant leaves the matrix untouched; a near-zero
3306    /// (ill-conditioned) determinant gives a finite but unreliable result, so
3307    /// inspect the returned determinant before trusting the matrix.
3308    fn mat3_inverse_inplace(m: &mut [Self; 3]) -> Self::Element;
3309
3310    /// 3x3 Matrix inversion.
3311    ///
3312    /// Returns `Some(inverse)`, or `None` if the matrix is exactly singular.
3313    /// Consider [`mat3_inverse_inplace`](Self::mat3_inverse_inplace) (which hands
3314    /// back the determinant) to avoid the copy and to use a custom tolerance.
3315    #[inline(always)]
3316    fn mat3_inverse(m: &[Self; 3]) -> Option<[Self; 3]> {
3317        let mut mat = *m;
3318        if Self::mat3_inverse_inplace(&mut mat) == Self::Element::ZERO {
3319            None
3320        } else {
3321            Some(mat)
3322        }
3323    }
3324
3325    /// "Normal matrix" for transforming normals under non-uniform scale, from
3326    /// the cofactor cross-products of a column-major 3x3.
3327    ///
3328    /// `DIVIDE = true` gives the true inverse-transpose `$(M^{-1})^{T}$` (non-finite if
3329    /// singular); `DIVIDE = false` gives the un-divided cofactor matrix, which is
3330    /// cheaper, never singular, and points normals the same direction (use it
3331    /// when you re-normalize the result). Cheaper than a full inverse either way.
3332    fn mat3_normal<const DIVIDE: bool>(m: &[Self; 3]) -> [Self; 3];
3333}
3334
3335/// Vector suitable for 4D linear algebra operations.
3336///
3337/// Must have exactly 4 lanes.
3338pub trait LinAlg4Vector: LinAlg3Vector {
3339    /// Scalar Product using all four lanes of the register as a 4D vector.
3340    fn dot4(self, other: Self) -> Self::Element;
3341
3342    /// Quaternion multiplication.
3343    ///
3344    /// Method:
3345    /// ```text
3346    /// T1 = (lhs.w * rhs)
3347    /// T2 = (lhs.x * rhs.wzyx) * {+,-,+,-}
3348    /// T3 = (lhs.y * rhs.zwxy) * {+,+,-,-}
3349    /// T4 = (lhs.z * rhs.yxwz) * {-,+,+,-}
3350    /// T1 + T2 + T3 + T4
3351    /// ```
3352    fn quat4_product(self, other: Self) -> Self;
3353
3354    /// Quaternion-vector multiplication.
3355    ///
3356    /// This is optimized to work best on various SIMD architectures. On
3357    /// architectures with permute/shuffle instructions, it uses the
3358    /// Double-Cross (Giesen) method. On architectures without such instructions,
3359    /// it falls back to the standard method of two dot products
3360    /// and a single cross product. This is because cross products require
3361    /// several shuffles/permutations to compute efficiently with SIMD.
3362    ///
3363    /// The `DOP` generic parameter indicates whether to use the
3364    /// "Difference of Products" method for computing the cross product(s),
3365    /// which can be more accurate in some cases, but _requires_
3366    /// hardware fused multiply-add instructions to be efficient.
3367    ///
3368    /// If you want the best performance, set `DOP` to `false`.\
3369    /// If you want the best accuracy or have FMA support, set `DOP` to `true`.
3370    fn quat4_vec3_product<const DOP: bool>(self, vec: Self) -> Self;
3371
3372    /// Rotation matrix of a **unit** quaternion as 3 registers; the 4th lane of
3373    /// each is unspecified.
3374    ///
3375    /// `COLUMN_MAJOR` picks the storage: the rotation's columns when `true`, its
3376    /// rows when `false` (i.e. the transpose). The choice is free - only the
3377    /// compile-time sign masks differ.
3378    ///
3379    /// Trig-free - the entries are pairwise products of `{x, y, z, w}`, no
3380    /// `sin`/`cos`/`sqrt`. The quaternion is assumed normalized.
3381    ///
3382    /// To rotate many vectors by one quaternion, convert once here and batch via
3383    /// [`mat3_vec3_product`](LinAlg3Vector::mat3_vec3_product) with the matching
3384    /// `COLUMN_MAJOR` - cheaper than a per-vector
3385    /// [`quat4_vec3_product`](Self::quat4_vec3_product) for large `N`.
3386    fn quat_to_mat3<const COLUMN_MAJOR: bool>(self) -> [Self; 3];
3387
3388    /// Homogeneous 4x4 rotation matrix of a **unit** quaternion: the
3389    /// [`quat_to_mat3`](Self::quat_to_mat3) rotation with each rotation
3390    /// register's 4th lane zeroed and a `[0, 0, 0, 1]` 4th register.
3391    /// `COLUMN_MAJOR` is forwarded to `quat_to_mat3`.
3392    fn quat_to_mat4<const COLUMN_MAJOR: bool>(self) -> [Self; 4];
3393
3394    /// 4x4 Matrix Transpose.
3395    fn mat4_transpose(m: &[Self; 4]) -> [Self; 4];
3396
3397    /// 4x4 Matrix-Vector multiplication, assuming `self` as the vector.
3398    ///
3399    /// The `COLUMN_MAJOR` generic parameter indicates whether the matrix
3400    /// is stored in column-major order (`true`) or row-major order (`false`).
3401    ///
3402    /// If the matrix is **NOT** in column-major order, it will need to be
3403    /// transposed before the actual multiplication, which will incur a performance penalty.
3404    ///
3405    /// NOTE: If you want to multiply 4 vectors by the same **column-major** matrix, consider using
3406    /// [`LinAlg4Vector::mat4_product`] instead. It is conceptually the same as multiplying each
3407    /// vector individually, but can take advantage of SIMD optimizations better.
3408    fn mat4_vec4_product<const COLUMN_MAJOR: bool>(self, m: &[Self; 4]) -> Self;
3409
3410    /// 4x4 Matrix-Vector3 multiplication, optimized for the case where the vector is a 3D coordinate
3411    /// (i.e., the 4th lane is ignored).
3412    ///
3413    /// The `COLUMN_MAJOR` generic parameter indicates whether the matrix
3414    /// is stored in column-major order (`true`) or row-major order (`false`).
3415    ///
3416    /// If the matrix is **NOT** in column-major order, it will need to be
3417    /// transposed before the actual multiplication, which will incur a performance penalty.
3418    fn mat4_vec3_product<const COLUMN_MAJOR: bool>(self, m: &[Self; 4]) -> Self;
3419
3420    /// 4x4 matrix multiplied with `N` 3D vectors (small-`N` batch; see
3421    /// [`mat4_vec4_product_array`](Self::mat4_vec4_product_array)).
3422    fn mat4_vec3_product_array<const COLUMN_MAJOR: bool, const N: usize>(
3423        m: &[Self; 4],
3424        vectors: &[Self; N],
3425    ) -> [Self; N];
3426
3427    /// 4x4 Matrix-Point3 multiplication, optimized for the case where the input 3D value is a
3428    /// point of homogenous coordinates (i.e. 4th lane is 1.0).
3429    ///
3430    /// The `COLUMN_MAJOR` generic parameter indicates whether the matrix
3431    /// is stored in column-major order (`true`) or row-major order (`false`).
3432    ///
3433    /// If the matrix is **NOT** in column-major order, it will need to be
3434    /// transposed before the actual multiplication, which will incur a performance penalty.
3435    fn mat4_point3_product<const COLUMN_MAJOR: bool>(self, m: &[Self; 4]) -> Self;
3436
3437    /// 4x4 Matrix multiplied with `N` 3D points (small-`N` batch).
3438    fn mat4_point3_product_array<const COLUMN_MAJOR: bool, const N: usize>(
3439        m: &[Self; 4],
3440        points: &[Self; N],
3441    ) -> [Self; N];
3442
3443    /// 4x4 Matrix-Matrix multiplication.
3444    ///
3445    /// If `COLUMN_MAJOR` is `false`, the matrices are assumed to be in row-major order,
3446    /// and the order of the multiplication will become `rhs * lhs` to account for that.
3447    /// This is mathematically equivalent to transposing both matrices, performing
3448    /// the multiplication, and then transposing the result, but is obviously more efficient.
3449    ///
3450    /// NOTE: When operating in column-major mode (`COLUMN_MAJOR = true`), the multiplication
3451    /// is effectively:
3452    /// ```text
3453    /// C0 = mat4_vec4_product(lhs, R0)
3454    /// C1 = mat4_vec4_product(lhs, R1)
3455    /// C2 = mat4_vec4_product(lhs, R2)
3456    /// C3 = mat4_vec4_product(lhs, R3)
3457    /// ```
3458    ///
3459    /// and is therefore, in **column-major order**, useful for transforming 4 vectors
3460    /// by the same matrix, but capable of being optimized better than doing
3461    /// 4 individual matrix-vector multiplications.
3462    fn mat4_product<const COLUMN_MAJOR: bool>(lhs: &[Self; 4], rhs: &[Self; 4]) -> [Self; 4];
3463
3464    /// Transform `N` vectors by a single 4x4 matrix, returning the transformed array.
3465    ///
3466    /// Intended for **small** `N` (a handful of points): the array is taken and
3467    /// returned **by value** and the loop fully unrolls, so a large `N` will
3468    /// bloat code size and stack usage. For large or dynamic counts, loop
3469    /// [`mat4_vec4_product`](Self::mat4_vec4_product) over a slice instead.
3470    ///
3471    /// Row-major matrices are transposed once up front (amortized over `N`).
3472    /// Backends with a true double-width register transform two vectors per pass.
3473    fn mat4_vec4_product_array<const COLUMN_MAJOR: bool, const N: usize>(
3474        m: &[Self; 4],
3475        vectors: &[Self; N],
3476    ) -> [Self; N];
3477
3478    /// In-place 4x4 Matrix inversion; **returns the determinant**.
3479    ///
3480    /// An exactly-zero determinant leaves the matrix untouched; a near-zero
3481    /// (ill-conditioned) determinant gives a finite but unreliable result, so
3482    /// inspect the returned determinant before trusting the matrix.
3483    fn mat4_inverse_inplace(m: &mut [Self; 4]) -> Self::Element;
3484
3485    /// Compute the determinant of a 4x4 matrix without inverting it.
3486    fn mat4_det(m: &[Self; 4]) -> Self::Element;
3487
3488    /// 4x4 Matrix inversion.
3489    ///
3490    /// Returns `Some(inverted_matrix)`, or `None` if the matrix is exactly
3491    /// singular. Consider [`Vector::mat4_inverse_inplace`] (which hands back the
3492    /// determinant) to avoid the copy and to use a custom tolerance.
3493    #[inline(always)]
3494    fn mat4_inverse(m: &[Self; 4]) -> Option<[Self; 4]> {
3495        let mut mat = *m;
3496
3497        if crate::likely(Self::mat4_inverse_inplace(&mut mat) != Self::Element::ZERO) {
3498            Some(mat)
3499        } else {
3500            None
3501        }
3502    }
3503}