We have considered using macros (see below), but we have not considered using macros with const-generics. If we use a macro it can just expand to __rustc_llvm_intrinsic_blend_(a, b, CONSTANT).
- What would be the advantage of using
const-generics here?
This is actually what clang does for some of the intrinsics. It just defines them using C macros. Since C macros are expanded without a bang (!), this allows clang to exactly match the vendor API.
The main advantage of using macros is they are not incompatible with adding the bare function later on if we ever get language support for them. That is, std could export foo! now, and add a std::arch::foo in the future without any issues.
The macros approach has a couple of smaller issues:
-
some intrinsics will be macros and some won’t. This is not a problem for those users who understand “why” this is the case, but it might be a minor inconvenience otherwise. Since nothing can go wrong here (you get a compiler error), this is pretty minor.
-
everything that wants to call them while still allowing users to pass a constant will need to be a macro as well . Arguably, the same can be said about const-generic based approaches.
-
macros might have a slightly larger impact on compile-times than bare functions or const generics. If only a fraction of your code uses the SIMD macros, one probably won’t care, but if you use them through higher-level SIMD libraries that might need to be macros as well, this might hit you a bit.
-
macros 2.0 aren’t there yet, so the macros would need to be exported by std. Re-exporting macros is not a thing either, so this might add some level of pain to libraries up the stack wanting to re-export the std macros in some cases, and overriding them in others. Macros 2.0 will fix all of these issues, so this isn’t a big deal either.
From the POV of stabilizing the intrinsics, the main goal is to stay as close to the C-like specs as possible. Using macros makes us deviate from the spec a bit. We already do so in other cases, so it can be done, but this pre-RFC explores one of the alternatives. Some other alternatives we have consider are:
- macros ! We use them internally to deal with this all over the place, we could just expose these macros to the user, and we don’t need const generics for it, so this wouldn’t block stabilization, and should be backwards compatible.
- Function attributes to prevent users from taking pointers to these API and for the compiler to emit an error if the arguments aren’t constants. This is half-way implemented into the compiler, and currently being tested. This approach makes the most sense to me as a temporary solution to something better, so this pre-RFC explores how that might look like.
- using const-generics in some form (this pre-RFC explores one of those forms, but others here have come up with great alternatives)
- not stabilize these APIs initially and re-evaluate first when const-generics lands (that is, require nightly in the mean time to use them): this is a no-go, some of these intrinsics are fundamental, and without them SIMD programming will take a serious hit (or become impossible).
I think once the function attribute approach is implemented, we will go over all the alternatives again and try to make a decision.