Masks

Rust also provides a “truthy” vector type: Mask<T, N>.

While operating like bool, the element type of a mask is always a signed integer. The size of the integer corresponds to the vector elements that the mask can interact with.

Masks operate like [bool; N], but their layout is unspecified and target-specific.

Elementwise operations with masks

Masks are typically produced by comparisons. Like vectors, they also support elementwise operations:

#![feature(portable_simd)]
fn main() {}
// mask32x4 is an alias for Mask<i32, 4>
//
// SimdPartialOrd is the elementwise counterpart to PartialOrd,
// and provides `simd_lt`, `simd_gt`, etc.
use std::simd::{f32x4, mask32x4, SimdPartialOrd};

fn is_between(x: f32x4, lower_bound: f32x4, upper_bound: f32x4) -> mask32x4 {
    let above_lower_bound: mask32x4 = x.simd_gt(lower_bound);
    let below_upper_bound: mask32x4 = x.simd_lt(upper_bound);
    above_lower_bound & below_upper_bound
}

Reduction operations

Masks also support reduction operations:

#![feature(portable_simd)]
fn main() {}
use std::simd::{f32x4, mask32x4, SimdFloat}; // SimdFloat provides is_infinite

fn any_infinite(vectors: &[f32x4]) -> bool {
    let mut infinite = mask32x4::splat(false);
    for v in vectors {
        infinite |= v.is_infinite();
    }
    
    // check if any element is `true`
    infinite.any()
}

Conditionally selecting elements

Masks can be used to conditionally select elements from two vectors:

#![feature(portable_simd)]
fn main() {}
use std::simd::{f32x4, mask32x4, SimdFloat}; // SimdFloat provides is_nan

/// replace nan values with 0
fn replace_nan(x: f32x4) -> f32x4 {
    let nans: mask32x4 = x.is_nan();
    nans.select(f32x4::splat(0.0), x)
}