-
Notifications
You must be signed in to change notification settings - Fork 12.7k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Provide a way to const-initialize vendor-specific vector types #48745
Comments
The following should work in nightly as soon as rust-lang/stdarch#338 is merged: const A: u32x8 = u32x8::new(1, 2, 3, 4, 5, 6, 7, 8);
let b: __m256i = A.into_bits(); However, IIUC @sfackler correctly, the problem is that we can't make If so, this has two causes:
First, we need to be able to do transmutes in Currently, these conversions have zero runtime cost, but as @sfackler mentions, they have an usability cost if they aren't Once we can perform const B: __m256i = mem::transmute(u32x8::new(1, 2, 3, 4, 5, 6, 7, 8)); In the longer term I would prefer if the following would just work: const B: __m256i = u32x8::new(1, 2, 3, 4, 5, 6, 7, 8).into_bits(); But we would need (*) EDIT: We could provide our own #![feature(const_fn, untagged_unions, stdsimd)]
use std::arch::x86_64::*;
use std::simd::u32x8;
// Marker trait for safe bitwise conversions
pub unsafe trait SafeFromBits<Other> {}
unsafe impl SafeFromBits<u32x8> for __m256i {}
mod simd {
#[allow(unions_with_drop_fields)]
union U<A, B> {
a: A,
b: B,
}
pub const fn transmute<A, B: ::SafeFromBits<A>>(x: A) -> B {
unsafe { U::<A, B> { a: x }.b }
}
}
static FOO: __m256i = simd::transmute(u32x8::new(1, 2, 3, 4, 5, 6, 7, 8));
fn main() {
println!("{:?}", FOO);
} Just because we can does not mean we should. I'd still prefer if |
The transmute is trivial. Trait methods are currently beyond the horizon (rust-lang/rfcs#2237 has been closed and is currently brainstormed out of band in https://github.com/Centril/rfc-effects) |
Why not make SIMD intrinsics |
I don't see any reason against doing that, at least for the intrinsics that initialize vectors. |
BTW it's already possible to use That do you think about other "pure" intrinsics? It could be left for later, but I think we should consider making them constant as well in future. |
Many intrinsics are pure, but most of them call |
https://rust.godbolt.org/z/s7bEEj3W9 use std::arch::x86_64::*;
use std::mem::transmute;
pub const FOO: __m256i = unsafe { transmute([1, 2, 3, 4, 5, 6, 7, 8]) };
#[target_feature(enable = "avx2")]
pub unsafe fn test() -> u32 {
_mm256_extract_epi32(FOO, 3) as u32
} example::test:
mov eax, 4
ret |
The platform independent simd types have constructors which are const fns, so they can be used in things like lookup tables: https://raw.githubusercontent.com/sfackler/stream-vbyte64/ea0d5b0afdf97f31473fafbf33d460fbbb313785/src/tables.rs.
However, the same is not the case for the vendor-specific types like
__m256i
. There are platform intrinsics which initialize those types (e.g._mm256_setr_epi32
is equivalent toi32x8::new
) but those are not const fns.One way to work around this is by type-punning through unions:
This kind of union is pretty common in SIMD-related C code I've seen, and I think well defined behavior from what the unions RFC describes. Is this the "right" way to do this? Can/should we make functions like
_mm256_set_epi32
const?cc @alexcrichton
The text was updated successfully, but these errors were encountered: