Skip to main content

Module vector

Module vector 

Source
Expand description

User-facing vector types and the trait hierarchy that defines them.

This module is the top of Thermite’s public API. It provides the Vector<R> newtype - the value you actually compute with - and the tower of traits (GenericVector and its descendants) that describe what a vector can do.

§Generic over behavior, not over a backend

The central idea of Thermite is that you write code against GenericVector (or a more specific trait like NumericVector, FloatVector, or IntegerVector) and let the caller pick the concrete type. That concrete type decides the ISA, the lane count, and the element type - your code does not name any of them:

use thermite::prelude::*;
use thermite::math::TranscendentalMath;

// Works on any backend, any width, any float element type.
fn gaussian<V: FloatVector + TranscendentalMath>(v: V) -> V {
    (-v * v).exp()
}

Crucially, “generic” here is stronger than “generic over the hardware backend”. A GenericVector is not required to be a dense array of scalars sitting in a hardware register at all. The trait describes an algebra of lanes, and anything that satisfies that algebra is a first-class vector.

§Composable abstractions all the way up

Because the trait bounds are the only contract, wrapper types that are not SIMD registers in any conventional sense can still implement the hierarchy and flow through the very same generic functions:

  • Complex numbers - a Complex<V> pairing two real vectors implements the GenericVector/FloatVector traits, so a function written for real FloatVectors operates transparently on complex data.
  • Compensated arithmetic - a double-double Compensated<V> that tracks rounding error implements the same traits; existing generic code gains extended precision just by being instantiated with it.
  • Dual / hyperdual numbers - automatic differentiation via the same trait composition, so a generic numeric routine differentiates itself when handed a dual type.

And these compose: Complex<Compensated<f32x8>> is a perfectly valid vector type where every complex operation is carried out in compensated real arithmetic, all still SIMD-accelerated underneath. The function you wrote once against FloatVector does not change.

§The trait hierarchy

Each trait adds capability on top of the previous one; bound on the least specific trait that supplies the operations you need.

GenericVector          construction, lane access, memory I/O, gather/scatter,
  |                    reinterpretation, map/fold/reduce, interleave
  |- BitwiseVector     &, |, ^, !, andnot, ternlog
  |   \- BitshiftVector   shifts, rotations, byte-shifts
  \- PartialOrdVector  cmp_lt/le/gt/ge/eq/ne -> Mask
      \- NumericVector    +, -, *, /, %, min/max/clamp, reductions, FMA
           |- SignedVector     abs, signum, copysign, neg
           |    \- FloatVector        sqrt, rcp/rsqrt, rounding, mix, consts
           |         \- FloatVectorWithBits  ldexp/frexp, bit-level ops
           \- IntegerVector    saturating/wrapping, popcount, dividers
                |              (also requires BitshiftVector)
                |- SignedIntegerVector    arithmetic shift, avg
                |                         (also requires SignedVector)
                \- UnsignedIntegerVector  is_power_of_two, parity, avg

FloatVector and SignedIntegerVector both sit under SignedVector; SignedIntegerVector additionally requires IntegerVector, so it is the meeting point of the signed and integer branches. IntegerVector itself does not require SignedVector - unsigned integer vectors are integers without being signed.

Alongside these, LinAlg3Vector/LinAlg4Vector add 3D/4D linear-algebra operations, and the Swizzle/Swizzle3/Swizzle4 traits add lane permutation. Masked (_c/_m/_z) variants of most operations live in the ops submodule.

Three layers cooperate to make all of this work: an Element (the scalar), a Register (the functional hardware layer), and Vector<R> (this module’s ergonomic wrapper). Most users only ever touch the Vector layer and its traits.

Re-exports§

pub use crate::register::StreamGroup;

Modules§

ops
Operator traits behind the vector arithmetic, plus the masked _c / _m / _z forms of each.
streaming
Non-temporal (streaming) vector loads and stores.
unaligned
Unaligned vector loads and stores, directly and via iterators.

Structs§

NumVector
Wraps a generic vector to provide implementations of num_traits traits.
ValueGroups
Lanes of a vector partitioned into groups of equal value, produced by group_by_value.
Vector
SIMD Vector type.

Traits§

AsFloatVectorWithBitsKernel
Some algorithms may benefit from being able to access the bitwise representation of floating point vectors. However, not all vectors support this functionality, and those that do may be passed as generic FloatVector. Therefore, this is a way of upcasting a FloatVector to a FloatVectorWithBits, if possible. If not possible, returns None.
BitCastVector
Zero-cost bit-level reinterpretation between vector types of the same size and lane count.
BitshiftVector
Shifts and rotates over the lanes of an integer vector, by an immediate, by a runtime scalar, or by a per-lane count.
BitwiseVector
Bitwise operations over the lanes of a vector: &, |, ^, !, bitandnot, and the arbitrary three-input ternlog.
CastVector
Per-lane numeric conversion between vector types.
Concat
Joining two HALF-width values into one double-width Self, and splitting back apart.
ConcatVector
Concat specialized to vector types: Self is a GenericVector that is the concatenation of two HALF vectors of the same element type, and whose mask is likewise the concatenation of two HALF masks.
Extend
Zero-extend a narrower FROM value into a wider Self, and narrow back.
ExtendVector
Zero-extend vectors
FloatVector
Floating-point vectors: the bound most user code should be written against.
FloatVectorWithBits
A FloatVector that additionally exposes its raw bit representation as companion integer vectors, enabling bit-level float algorithms.
FloatVectorWithRegister
Float vector types which have an associated hardware register type.
FullyInteroperable
PartiallyInteroperable plus zero-cost bit-level reinterpretation (BitCastVector) among Self, A, and B.
GenericVector
Core trait for generic vector types.
GenericVector2
Convenience accessors x() / y() automatically available on any 2-lane GenericVector.
GenericVector3
Convenience accessors x() / y() / z() automatically available on any 3-lane GenericVector.
GenericVector4
Convenience accessors x() / y() / z() / w() automatically available on any 4-lane GenericVector.
IndexableVector
A vector type that supports gather/scatter using index vectors of type I.
IntegerVector
Vectors of integer elements.
Interleave
Pairwise lane interleaving and its exact inverse, the building block for moving between array-of-structs and struct-of-arrays layouts.
LinAlg3Vector
Vector suitable for 3D linear algebra operations.
LinAlg4Vector
Vector suitable for 4D linear algebra operations.
MaskInteroperable
Three vector types (Self, A, B) whose masks can all be freely cast to one another.
NewConst
Carrier for a compile-time constant array of N per-lane values of element type E.
NewVector
A vector type that can build a constant of itself from a compile-time NewConst array carrier.
NumericVector
Vectors that support arithmetic and comparison operations on their elements.
PackedFloatVector
A u16/u8 integer vector reinterpreted as a vector of packed floats (format S: fp16, bfloat16, the fp8 variants, …), transcodable to and from the wider f32 vector F of the same lane count.
PartialOrdVector
Per-lane comparison producing a Mask.
PartiallyInteroperable
MaskInteroperable plus bidirectional numeric (CastVector) conversion among Self, A, and B.
Sad16Vector
A u8 vector whose absolute differences can be summed in groups of 2 byte-lanes into the u16 vector W (same total width, LANES / 2 output lanes).
Sad32Vector
A u8 vector whose absolute differences can be summed in groups of 4 byte-lanes into the u32 vector W (same total width, LANES / 4 output lanes).
Sad64Vector
A u8 vector whose absolute differences can be summed in groups of 8 byte-lanes into the u64 vector W (same total width, LANES / 8 output lanes) - x86 PSADBW semantics.
SignedIntegerVector
The operations that need both a sign and integer lanes: arithmetic (sign-filling) right shifts, the overflow-free averages, and the rounded high-half multiply.
SignedIntegerVectorWithRegister
SignedBits integer vector types which have an associated hardware register type.
SignedVector
Vectors whose elements can represent negative values.
SplatConst
Simple associated constant splat trait.
SplatVector
A vector type that can splat a compile-time SplatConst carrier into a constant of itself.
Swizzle3
Only available for “3-lane” (ignoring 4th lane) LinAlg3Register vectors, this allows human-readable swizzle/permutations of the vector. Permutations will ignore the 4th lane of the register, leaving it unchanged.
Swizzle4
Only available for 4-lane vectors, this allows human-readable swizzle/permutations of the vector.
SwizzleVector
A GenericVector whose lanes can be permuted by the Swizzle machinery for its lane count.
UnsignedIntegerVector
The operations that read better on unsigned lanes: the power-of-two and inclusive-range predicates, and the unsigned averages.
UnsignedIntegerVectorWithRegister
Unsigned integer vector types which have an associated hardware register type.
VectorIndices
An unsigned integer vector that can be used as the index operand for gather/scatter operations producing/consuming a vector of type V.
VectorValue
Associates a constant carrier C with the concrete vector constant V it produces.
VectorWithRegister
Escape hatch tying a Vector to its specific underlying Register type.

Functions§

const_new
Build a vector V from the compile-time constant per-lane array carried by C.
const_splat
Build a vector V with every lane set to the compile-time constant carried by E.