-
Notifications
You must be signed in to change notification settings - Fork 13.3k
const
function arguments for intrinstrics/simd
#47980
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
Comments
This "ideal solution" seems like it's strictly weaker than, and subsumed by, const generics. |
@rkruppe I agree, but I think that semantics do matter: void bar(char, const char, char, const char); I think it is a major ergonomic improvement for users to be able to map that to: fn bar(u8, const u8, u8, const u8); instead of directly using fn bar<const u8, const u8>(u8, u8, u8); Obviously, I expect both features to be able to do the same thing, and I expect Does that make sense? Or in other words, yes I agree with you, this would just be "nicer" syntax for some use-cases of |
Mapping void foo(const u8); to fn foo(const _: u8); would be wrong. It means something very different (as you said), even though some vendors have abused this notation in C. If people are really going to use If it's truly just syntactic sugar for a specific kind of const generics, then it certainly doesn't block stabilization of intrinsics (or anything else, for that matter), so I don't understand most of the inital post in that light. Also, I'd rather gather experience with plain old const generics before adding sugar for specific use cases (just as we've had a lot of experience with type generics before adding |
Well, we don't have Also, IIUC the
It would be wrong in C. But the specs are not C, the specs are in a language that looks like C but where When it comes to real C, then yes, |
You're right that it's possible to implement this feature without implementing everything required for const generics. However, if you're proposing that, this feature can't be justified as being just sugar for const generics, since it predates const generics and may turn out to be incompatible with the exact form of const generics eventually adopted. In particular, const generics may wind up having some restrictions on what sorts of values can be used as const arguments -- are we sure this feature will have the same restrictions (and do we even want it to?). But I am quite opposed to adding an ad hoc feature just to be able to stabilize some feature a bit (possibly only in the order of months) sooner. If we add this feature, I think it needs to be justified independently and stand on its own.
I may have misunderstood you. The user base of C is much larger, and the semantics of C are much more well known, therefore I could understand an argument based on analogy to C (even though I'd disagree for reasons stated). If you're only talking in analogy to that vendor documentation, I don't understand this statement (emphasis mine):
Translating those documents to Rust signatures is a one-time job for expert users, and syntactic differences are the least of the problems involved. I don't think making it a tiny bit easier to transliterate those documents to Rust is even remotely enough justification to add any language feature. 99.99% of Rust users (including those that use the intrinsics) would not benefit at all from it. |
We can be conservative.
Fair enough.
Every abstraction over SIMD until the end user must do this, and the end user must not pass these abstractions run-time values. |
Sure, but we need to be absolutely certain we're conservative enough to be forward compatible with const generics. And the more conservative we are, the less general and appealing this feature is as a feature of its own.
Good point, but those people can (and probably should) reference the signatures in stdsimd (edit: or whatever layer of abstraction they're building on). Doing that saves them the entire effort of transliterating the signature (edit: and any effort for mapping to a higher level of abstraction, if they build on one), while matching vendor documentation only makes the transliteration minimally simpler. Not to mention that I don't think it's an undue burden to convert "const arguments" to const generics while transliterating the syntax. It's just one more minor syntactic difference. |
What do you mean? |
Someone who writes an abstraction over stdsimd should (and hopefully will) look at the stdsimd signatures to help write their own library's signatures, rather than going all the way back to the vendor documentation. Likewise, someone who writes an abstraction over a higher level SIMD library will look at that library's function signatures, not at any of the layers below. So similarity to the vendor documentation is at most relevant for the lowest level of the stack, the people creating stdsimd. |
The problem is that EDIT: For example, something like this in the wrapper over pub trait U16Constant {
const X: u8;
}
pub fn barbaz<T: U16Constant>(x: u16) {
coresimd::barbaz(x, T::X)
} and like this in user code of that library: use supersimd::{U16Constant, barbaz};
struct Leet;
impl U16Constant for Leet { const X: u8 = 1337; }
barbaz::<Leet>(4); It can be done, but, I think its suboptimal. That's all. |
I am well aware and agree this is a problem that needs solving. I was talking solely about the "it looks closer to vendor documentation which makes it easier to write the equivalent Rust signature" angle and arguing that only the stdsimd authors, and nobody else, needs to reverse engineer a rust signature out of vendor docs or C headers. |
As this is proposing a new language feature, I believe it will need an RFC, and thus should live over on https://github.com/rust-lang/rfcs |
I'll post a pre-RFC in internals when I have the time. |
Problem
Many intrinsics, in particular, many SIMD intrinsics, work only on immediate-mode registers. We can currently implement them in the compiler directly, handling constant function arguments in the implementation.
This doesn't allow users to easily build abstractions on top of these intrinsics because they can't do what the compiler can do. Abstractions can, however, be built (I show what the
stdsimd
crate does below).Currently, for many intrinsics, we don't do this in the compiler, but in libraries, like the
stdsimd
crate (check out, for example, _mm_i32gather_epi32).In the
stdsimd
crate, new contributors typically clash against our workarounds for dealing with these intrinsics pretty early on, often in their first pull-request (e.g. see rust-lang/stdarch#311).The API of these intrinsics in the
stdsimd
crate uses run-time valuesand then it uses
constify_xxx!
macros likeconstify_imm8!
to map these run-time values into compile-time constants:These
constify
macros just match against every possible run-time value, and call a function with a constant:The status quo does not scale, neither for those wanting to write higher-level wrappers over the
stdsimd
crate, nor for some of the intrinsics that require huge match arms (e.g.bextri
is currently disabled becauseconstify_imm16!
makes the compile-times of thestdsimd
crate explode from 1-3 minutes to ~30 minutes).Ideal solution
I would like to be able to specify that a function argument must be const:
This is what the Intel spec tries to specify when it uses
const int
. It fails because in Cconst
does not mean the same thing as in Rust, but this makes it an opportunity: Rust could follow the C spec better than C does.Alternatives
We could just implement these intrinsics in rustc. There are many many of them, but this can be done. Rustc actually already does this for many intrinsics, and errors of arguments not being constants are already reported.
The main issues I see with this is that
Moving these intrinsics into the compiler would allow us to stabilize simd without having to wait for
const
function arguments or equivalent language features.The text was updated successfully, but these errors were encountered: