How should I write generic SIMD code without putting massive requirements into my where clauses?
⚓ Rust 📅 2025-12-17 👤 surdeus 👁️ 1I have a lot of SIMD code that relies on a function that looks like this:
#![feature(portable_simd)]
use std::simd::prelude::*;
use std::simd::*;
unsafe fn do_things<T, const L: usize>(
x: Simd<T, L>,
cmp: Simd<T, L>,
tests: &[T],
) -> Simd<T, L> where
LaneCount<L>: SupportedLaneCount,
T: SimdElement + Default,
Simd<T, L>: SimdPartialOrd,
Mask<isize, L>: From<<Simd<T, L> as SimdPartialEq>::Mask>,
{
// this function is mostly nonsense but uses real operations from my code
let results: Mask<isize, L> = x.simd_le(cmp).into();
let offsets = results.to_int();
let ptrs = Simd::splat(tests.as_ptr()).wrapping_offset(offsets);
unsafe { Simd::gather_ptr(ptrs) }
}
(this is not the "real" function, but an abstracted version of this, if you want to see the exact version).
In the ideal world, I would like to be able to have user-facing library have a much simpler signature that also does not leak all the implementation details :
// the below traits will be sealed to avoid leaking
pub trait MyTrait {} // can modify this however I like
pub trait MySimdTrait {} // and this too
pub fn public_math<T, const L: usize>( /* ... */ ) where
T: MyTrait,
Simd<T, L>: MySimdTrait,
LaneCount<L>: SupportedLaneCount,
{
// do other things...
unsafe { do_things::<T, L>(/* ... */) };
// ...
}
So far, I've been decently successful at just requiring that T and Simd<T, L> support certain traits, but specifically the following requirement has caused me a lot of grief:
Mask<isize, L>: From<<Simd<T, L> as SimdPartialEq>::Mask>,
since I can't seem to be able to capture it into MyTrait or MySimdTrait. I have a few questions:
- Is it possible to avoid this trait requirement altogether in
do_things? - If not, is it possible to fold the requirement into
MyTraitorMySimdTrait? - In general, is there a better way to do this? Can I reduce the number of traits and where clauses somehow?
2 posts - 2 participants
🏷️ Rust_feed