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
Add feature to disable aesni target feature compile time checks #22
Conversation
Problem with such feature is that intrinsics will not get inlined in such setup, which will severely impact performance. I am not sure if I guess this PR can be merge for now, but ideally we need the language support for such use-cases. @gnzlbg |
The problem is that this crate requires I don't really understand why it was designed this way. A better design would be to have the crate just use This allows those who want to do run-time feature detection for This also allows those using compile-time feature detection to use the crate by just writing: You can then provide safe APIs on top of this in this same crate or other crates. For example: #[cfg(target_feature = "aes")]
pub mod ct { // compile-time
pub fn foo() { unsafe { ::foo() /* always inlined */ } }
}
//^^^ or move this to another crate and use compile_error! for a nice error message
// you could also provide this, but that is probably a bad idea because of inlining
pub mod rt { // run-time
pub fn foo() {
if is_x86_feature_detected!("aes") {
unsafe { ::foo() /* never inlined */ }
} else {
// panic!();
// fallback_foo();
// Err(...) ...
}
}
}
If a user writes in their own crate: fn my_alorithm() {
if is_x86_feature_detected!("aes") {
unsafe { foo() }
}
}
#[target_feature(enabled = "aes")]
unsafe fn foo() {
// calls to aesni functions
} All OTOH, In any case, for libraries, compile-time feature detection is almost always a bad idea. Whether features are detected at compile-time or run-time is something that applications should control. If you make the decision in a library, then you cut half the world for which this might be the wrong decision / trade-off from using the library. Arguably, having to make your APIs |
The main reason for the current design is that block ciphers expose their functionality via I guess as a stop-gap solution I could expose trait-less feature-gated unsafe methods with |
That is probably a good step forward. You can reuse these in the safe ones by just calling them via an
There is a "pattern" in the wild which allows you to provide a safe API that performs run-time feature detection once, while letting your users control when that happens: [derive(Clone, Copy, Debug)]
pub struct AesniBuilder(());
impl AesniBuilder {
pub fn new() -> Option<AesniBuilder> {
if is_x86_feature_detected!("aes") {
Some(AesniBuilder(()))
} else {
None
}
}
#[inline]
// maybe also:
// #[target_feature(enable = "aes")]
// unsafe
fn foo() { unsafe { aesni::foo() } }
} People are using it without Then, whether the user wants to construct a new builder every time, or put one in the whole program behind a static, that kind of is up to them. |
It's not only about annoyance of |
The language already supports this. If you just write plain old portable Rust, you can compile the same function for multiple target features. However, you have specifically decided to 1) use an |
My wording was a bit unclear, I've meant that if you'll use function |
I still don't understand what you mean here.
Enabled how exactly? If you enable them for your whole binary, it doesn't really matter. Here the user doesn't have them enabled for their whole binary but an upstream crate requires that, and therefore, they can't use the crate. |
With The system which I've tried to describe will be able to compile the following code: #[target_feature(enable = "aes")]
unsafe fn aesni_encrypt(data: &mut [u8]) {
// use aesni crate here
}
if is_x86_feature_detected!("aes") {
unsafe { aesni_encrypt(block) };
} else {
// software AES
soft_encrypt(block);
} Because If somewhere in the code And if in addition to the previous two target feature contexts I guess it was just an ersatz of target restriction contexts idea. |
But that code already compiles in Rust, just exactly as you wrote it :D
Wouldn't that break separate compilation, in that you would have to wait till you use a crate to know how to compile it (e.g. which target features to enable), but you can't use the crate yet, because you haven't compiled it? Maybe you are looking for // crate A
#[inline]
fn foo() {}
// crate B
#[target_feature(enable = "avx2")]
unsafe fn bar() { foo() } // foo is compiled with AVX2 |
No, with the current version of Also IIUC
I guess, yes, it will. Technically it's possible to work around this issue (e.g. by compiling crate without features first and postponing any errors until crate will be used in feature-less context), but overall I agree it was not the best idea.
No, I am using target feature based |
I think I missed the
While you could use
Features affect everything since you can do conditional compilation with So at least with the current system, I don't think this is technically possible. One would need probably many language features and technical work to come up with a system here that makes sense and works as the user expects. |
But it's not a single functions, all functions and structs in the crate require enabled I guess for now we will have to use feature for disabling target feature checks. Personally I don't think that builder pattern proposed earlier is a good solution to the problem in this particular case. @cheme |
When using runtime
is_x86_feature_detected
macro to check if I could use aesni, I had to disable the checks.Is it possible to include this little feature to allow usage of aesni without compile time checks?