A more convenient #[target_feature] replacement

To get good performance out of SIMD everything on the SIMD codepath must be inlined. With how SIMD is currently implemented in Rust one of two things have to be true for a function using SIMD to be inlinable: (and this includes the SIMD intrinsics themselves)

a) The whole program has to be compiled with the relevant -C target-cpu or -C target-feature flags.

b) SIMD support must be automatically detected at runtime, and every function on the SIMD codepath must be marked with #[target_feature].

Both have their downsides. Setting the target-cpu or target-features makes the resulting binary incompatible with older CPUs, while using #[target_feature] is incredibly inconvenient.

This crate is meant to make #[target_feature] less painful to use.

Problems with #[target_feature]

When we're not compiling with the relevant target-cpu/target-feature flags everything on the SIMD codepath must be marked with the #[target_feature] attribute. This is not a problem when all of your SIMD code is neatly encapsulated inside of a single function, but once you start to build out more elaborate abstractions it starts to become painful to use.

How does this crate make it better?

You can now mark safe functions with #[target_feature]

This crate exposes an #[unsafe_target_feature] macro which works just like #[target_feature] except it moves the unsafe from the function prototype into the macro name, and can be used on safe functions.

``rust,compile_fail // ERROR:#[target_feature(..)]can only be applied tounsafe` functions

[target_feature(enable = "avx2")]

fn func() {} ```

``rust // It works, but must beunsafe`

[target_feature(enable = "avx2")]

unsafe fn func() {} ```

```rust use curve25519dalekderive::unsafetargetfeature;

// No unsafe on the function itself!

[unsafetargetfeature("avx2")]

fn func() {} ```

It can also be used to mark functions inside of impls:

```rust,compile_fail struct S;

impl core::ops::Add for S { type Output = S; // ERROR: method add has an incompatible type for trait #[target_feature(enable = "avx2")] unsafe fn add(self, rhs: S) -> S { S } } ```

```rust use curve25519dalekderive::unsafetargetfeature;

struct S;

[unsafetargetfeature("avx2")]

impl core::ops::Add for S { type Output = S; // No unsafe on the function itself! fn add(self, rhs: S) -> S { S } }

```

You can generate specialized copies of a module for each target feature

```rust use curve25519dalekderive::unsafetargetfeature_specialize;

[unsafetargetfeature_specialize("sse2", "avx2", conditional("avx512ifma", nightly))]

mod simd { #[fortargetfeature("sse2")] pub const CONSTANT: u32 = 1;

#[for_target_feature("avx2")]
pub const CONSTANT: u32 = 2;

#[for_target_feature("avx512ifma")]
pub const CONSTANT: u32 = 3;

pub fn func() { /* ... */ }

}

fn entrypoint() { #[cfg(nightly)] if std::isx86featuredetected!("avx512ifma") { return simd_avx512ifma::func(); }

if std::is_x86_feature_detected!("avx2") {
    return simd_avx2::func();
}

if std::is_x86_feature_detected!("sse2") {
    return simd_sse2::func();
}

unimplemented!();

} ```

How to use #[unsafe_target_feature]?

License

Licensed under either of

at your option.

Contribution

Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in the work by you, as defined in the Apache-2.0 license, shall be dual licensed as above, without any additional terms or conditions.