Rust
Mask
Do conditional packed operations with Mask.
Masks
In SIMD, comparisons produce not a single bool but a mask with one bool per lane. Masks are used with select instead of branching: for each lane, the value is taken either from one vector or the other. This gives conditional processing without if:
// nightly std::simd
let a = i32x4::from_array([1, 5, 3, 8]);
let m = a.simd_gt(i32x4::splat(4)); // [false, true, false, true]
let c = m.select(a, i32x4::splat(0)); // [0, 5, 0, 8]
Branchless code also avoids the processor's branch misprediction penalty on unpredictable conditions.
Masks and selection with arrays
We can write the same idea in stable Rust with arrays; the structure is a branchless form the compiler can vectorize:
fn buyuk_mu(a: [i32; 4], esik: i32) -> [bool; 4] {
a.map(|x| x > esik)
}
fn sec(m: [bool; 4], a: [i32; 4], b: [i32; 4]) -> [i32; 4] {
std::array::from_fn(|i| if m[i] { a[i] } else { b[i] })
}
[T; N]::map applies a closure to each element and returns a new array.
Exercise Mask and select
Write the buyuk_mu and sec functions above. For a = [1, 5, 3, 8] and threshold 4, print the mask and the result of sec(m, a, [0; 4]) with {:?}, separated by a space.
Show example solution
fn buyuk_mu(a: [i32; 4], esik: i32) -> [bool; 4] {
a.map(|x| x > esik)
}
fn sec(m: [bool; 4], a: [i32; 4], b: [i32; 4]) -> [i32; 4] {
std::array::from_fn(|i| if m[i] { a[i] } else { b[i] })
}
fn main() {
let a = [1, 5, 3, 8];
let m = buyuk_mu(a, 4);
println!("{:?} {:?}", m, sec(m, a, [0; 4]));
}
Test yourself
-
Why are masks used instead of <code>if</code> in SIMD?
- Convention
- Masks are unnecessary
- Lanes run the same instruction together; there's no separate branch per lane
- if compiles slowly
Show answer
Lanes run the same instruction together; there's no separate branch per lane — Both branches' results are computed and the mask picks which to keep.
-
Array map
fn buyuk_mu(a: [i32; 4], esik: i32) -> [bool; 4] {
a.____(|x| x > esik)
}
Show answer
fn buyuk_mu(a: [i32; 4], esik: i32) -> [bool; 4] {
a.map(|x| x > esik)
}
-
Operation and result (a = [1, 5, 3, 8])
- a > 4
- [false, true, false, true]
- sec(m, a, [0; 4])
- [0, 5, 0, 8]
- a > 0
- [true, true, true, true]
- a > 10
- [false, false, false, false]
Next lesson: Horizontal ops