npsimd 0.3.0

An ergonomic library for architecture-specific vectorization.
Documentation
//! Internal SIMD types.
//!
//! The types defined here are marked with the special `repr(simd)` attribute.
//! These are specially recognized by the compiler as SIMD vector types.

/// A SIMD vector type.
///
/// # Safety
///
/// A type `T` can soundly implement `Vector` if and only if all of the
/// following conditions are satisfied:
///
/// - `T` is uses `repr(simd)`.
/// - `T::LEN` is a power of two.
/// - `T::Array` is an array type of the form `[T::Elem; T::LEN]`.
/// - The size of `T` is the same as the size of `T::Array`.
/// - It is sound to transmute between `T` and `T::Array`.
///
/// Note that the fields of `T` need not have the same type as `T::Elem`; for
/// example, a `T` with `T::Array = [u64; 2]` can be defined as 4 `u32`s.  This
/// allows `T::Elem` to be an aggregate or other non-primitive type.
pub unsafe trait Vector: Copy {
    /// The element type of this vector.
    type Elem: Copy;

    /// The array type corresponding to this vector.
    type Array: Copy;

    /// The number of elements in this vector.
    const LEN: usize;

    /// Broadcast an element to every position of this vector.
    ///
    /// # Safety
    ///
    /// This method should only be used with elements that are known at
    /// compile-time, as there is no general and efficient way to do so at
    /// runtime.
    unsafe fn splat(elem: Self::Elem) -> Self;
}

/// A macro to define a SIMD vector type.
macro_rules! decl_simd_type {
    (
        $name:ident
        [$elem:ty; $size:literal],
        ($($rest:tt)*), $doc:tt
    ) => {
        decl_simd_type!($name[$elem; $size]($elem), ($($rest)*), $doc);

        unsafe impl Vector for $name {
            type Elem = $elem;
            type Array = [$elem; $size];
            const LEN: usize = $size;

            unsafe fn splat(elem: Self::Elem) -> Self {
                impl_array_vector!(Self(elem,), $($rest,)*)
            }
        }
    };

    // For every size token, double the number of elements.
    (
        $name:ident
        [$elem:ty; $size:literal]
        ($($field:ty),+),
        ($_:tt $($rest:tt)*),
        $doc:tt
    ) => {
        decl_simd_type!(
            $name
            [$elem; $size]
            ($($field),+, $($field),+),
            ($($rest)*),
            $doc
        );
    };

    // If there are no size tokens left, output the declaration.
    (
        $name:ident
        [$elem:ty; $size:literal]
        ($($field:ty),+),
        (),
        $doc:tt
    ) => {
        #[doc = $doc]
        #[allow(non_camel_case_types)]
        #[allow(dead_code)] // TODO: Remove
        #[derive(Copy, Clone, Debug, PartialEq)]
        #[repr(simd)]
        pub struct $name($(pub(crate) $field),+);
    };
}

// Vectors of 8-bit integers.

decl_simd_type!(u8x2[u8; 2], (1),
    "A vector of 2 unsigned 8-bit integers.");

decl_simd_type!(u8x4[u8; 4], (1 2),
    "A vector of 4 unsigned 8-bit integers.");

decl_simd_type!(u8x8[u8; 8], (1 2 4),
    "A vector of 8 unsigned 8-bit integers.");

decl_simd_type!(u8x16[u8; 16], (1 2 4 8),
    "A vector of 16 unsigned 8-bit integers.");

decl_simd_type!(u8x32[u8; 32], (1 2 4 8 16),
    "A vector of 32 unsigned 8-bit integers.");

decl_simd_type!(u8x64[u8; 64], (1 2 4 8 16 32),
    "A vector of 64 unsigned 8-bit integers.");

decl_simd_type!(s8x2[i8; 2], (1),
    "A vector of 2 signed 8-bit integers.");

decl_simd_type!(s8x4[i8; 4], (1 2),
    "A vector of 4 signed 8-bit integers.");

decl_simd_type!(s8x8[i8; 8], (1 2 4),
    "A vector of 8 signed 8-bit integers.");

decl_simd_type!(s8x16[i8; 16], (1 2 4 8),
    "A vector of 16 signed 8-bit integers.");

decl_simd_type!(s8x32[i8; 32], (1 2 4 8 16),
    "A vector of 32 signed 8-bit integers.");

decl_simd_type!(s8x64[i8; 64], (1 2 4 8 16 32),
    "A vector of 64 signed 8-bit integers.");

// Vectors of 16-bit integers.

decl_simd_type!(u16x2[u16; 2], (1),
    "A vector of 2 unsigned 16-bit integers.");

decl_simd_type!(u16x4[u16; 4], (1 2),
    "A vector of 4 unsigned 16-bit integers.");

decl_simd_type!(u16x8[u16; 8], (1 2 4),
    "A vector of 8 unsigned 16-bit integers.");

decl_simd_type!(u16x16[u16; 16], (1 2 4 8),
    "A vector of 16 unsigned 16-bit integers.");

decl_simd_type!(u16x32[u16; 32], (1 2 4 8 16),
    "A vector of 32 unsigned 16-bit integers.");

decl_simd_type!(s16x2[i16; 2], (1),
    "A vector of 2 signed 16-bit integers.");

decl_simd_type!(s16x4[i16; 4], (1 2),
    "A vector of 4 signed 16-bit integers.");

decl_simd_type!(s16x8[i16; 8], (1 2 4),
    "A vector of 8 signed 16-bit integers.");

decl_simd_type!(s16x16[i16; 16], (1 2 4 8),
    "A vector of 16 signed 16-bit integers.");

decl_simd_type!(s16x32[i16; 32], (1 2 4 8 16),
    "A vector of 32 signed 16-bit integers.");

// Vectors of 32-bit integers.

decl_simd_type!(u32x2[u32; 2], (1),
    "A vector of 2 unsigned 32-bit integers.");

decl_simd_type!(u32x4[u32; 4], (1 2),
    "A vector of 4 unsigned 32-bit integers.");

decl_simd_type!(u32x8[u32; 8], (1 2 4),
    "A vector of 8 unsigned 32-bit integers.");

decl_simd_type!(u32x16[u32; 16], (1 2 4 8),
    "A vector of 16 unsigned 32-bit integers.");

decl_simd_type!(s32x2[i32; 2], (1),
    "A vector of 2 signed 32-bit integers.");

decl_simd_type!(s32x4[i32; 4], (1 2),
    "A vector of 4 signed 32-bit integers.");

decl_simd_type!(s32x8[i32; 8], (1 2 4),
    "A vector of 8 signed 32-bit integers.");

decl_simd_type!(s32x16[i32; 16], (1 2 4 8),
    "A vector of 16 signed 32-bit integers.");

// Vectors of 64-bit integers.

decl_simd_type!(u64x1[u64; 1], (),
    "A vector of 1 unsigned 64-bit integer.");

decl_simd_type!(u64x2[u64; 2], (1),
    "A vector of 2 unsigned 64-bit integers.");

decl_simd_type!(u64x4[u64; 4], (1 2),
    "A vector of 4 unsigned 64-bit integers.");

decl_simd_type!(u64x8[u64; 8], (1 2 4),
    "A vector of 8 unsigned 64-bit integers.");

decl_simd_type!(s64x1[i64; 1], (),
    "A vector of 1 signed 64-bit integer.");

decl_simd_type!(s64x2[i64; 2], (1),
    "A vector of 2 signed 64-bit integers.");

decl_simd_type!(s64x4[i64; 4], (1 2),
    "A vector of 4 signed 64-bit integers.");

decl_simd_type!(s64x8[i64; 8], (1 2 4),
    "A vector of 8 signed 64-bit integers.");