SIMD now available in libstd on nightly!

https://doc.rust-lang.org/nightly/std/arch/

As of last night’s nightly the stdsimd project has been integrated into the standard library and is available in libstd/libcore. The std::arch module now has a ton of x86/x86_64 intrinsics ripe for testing!

If you’re interested in using SIMD in Rust please kick the tires on this module and the associated language features! You can find some examples in the module documentation or you can jump straight into the playground!

43 Likes

FASTER REBASE TIME :tada::tada::tada::tada::tada::tada:

Looks great; here’s hoping for a constructive stabilization process!

2 Likes

aesni crate migrated to the coresimd from inline assembly and I am happy to drop it as an explicit dependency!

Although I must note that I am bit dissatisfied with ergonomics around enabling target features using RUSTFLAGS (yes, you can use .cargo/config, but it’s still far from ideal) and with lack of compile time checks around target features (which results in all intrinsics being unsafe). I’ll try to write a post about how I see it ideally should work.

Also currently I have to disable doctests if I want to produce a readable error with compile_error!(..) in case if users forgot to enable aes target feature, due to the fact that doctests build process ignores RUSTFLAGS. (this issue marked as closed, but I think it should be reopened)

2 Likes

Please see Minimal target feature unsafe by hsivonen · Pull Request #2212 · rust-lang/rfcs · GitHub for ongoing work on that front.

(Nobody is happy about the intrinsics being unsafe.)

Very nice! Is there any plan to enable #[target_feature] attributes for things other than functions? For example, I’d expect that applying #[target_feature] to a module or an impl would be the same as applying it to every function or method in that module or impl. Instead, it seems to currently result in an ICE.

Yes, I know about this RFC, but I don’t think it’s the best approach either. I had in mind a more general solution which will encompass not only target features, but also other target parameters as well. The basic idea is to keep target restrictions context for all items (including modules and crates) and to allow for selected items to restrict this context even further. (i.e target restrictions will be cascade, sub-item can not be less restricted than its parent, e.g. crate) The next step is to check if all used items fit into restriction contexts. (i.e. it will be impossible to use sse4 intrinsic in the context without restriction on enabled sse4 target feature) And the last step is to introduce compile time and runtime dispatch macros (they will have to be the language built-ins) which will allow us to create more restricted sub-contexts:

// use runtime detection to select which arm to execute
let result = runtime_dispatch!(
    (feature=("avx2" && "sse4.1")) => foo_avx2_sse41(),
    (feature="sse2") => {
        // e.g. here we can call SSE2 intrinsics safely
        let c = _mm_add_epi64(a, b);
    },
    _ => foo(), // fallback function
);
// select one of the arms at compile time and inline it into the code
let result = compiletime_dispatch!(bar,
    (os="linux", feature="aes") => bar_linux_aes(),
    (os="linux") => { ... },
    (os="windows") => bar_windows(),
    _ => bar(), // fallback function
);

(this is just a rough draft)

Thus all intrinsics will be safe, but it will be impossible to use them without introducing appropriate restrictions to the context in which they will be used.

And of course this approach asks for integration with cargo, so we will be able to specify in the Cargo.toml that crate is e.g. for windows only, or unconditionally depends on some target features, etc. And by having this information we will be able to better work with [target.'cfg(..)'.dependencies], so compiler at compile time will not allow e.g. to use windows-only dependency for linux only application, or sse4 dependent crate in the application without either adding this restriction to the application Cargo.toml or by providing some sort of fallback. And if crate will specify crate-level target restriction it will be compiled with the enabled features without requiring to use RUSTFLAGS.

This approach can be seen as a generalization of RFC 1868. I fully understand that this proposal is quite large overhaul of the currently existing #[cfg(..)] based manual approach and will require significant internal changes. Also in the worst case scenario it could require addition of a SAT solver to the compiler to evaluate if item can be used in the given restriction context. (although I hope with some reasonable restrictions we will be able to proceed without it)

But nevertheless it’s how I, as a user, see Rust ideally should work with target parameters. While this description is quite messy, I hope that the main idea is more or less conveyed. I’ll try to write a more detailed pre-pre-RFC later.

1 Like

My Cortex M build failed yesterday with “Can’t find coresimd/mod.rs”. Did I just get unlucky or is something for fundamentally broken on embedded targets that needs reporting?

https://travis-ci.org/thejpster/monotron/builds/349035062

$ xargo build --release
   Compiling core v0.0.0 (file:///home/travis/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/src/libcore)
error: couldn't read "/home/travis/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/src/libcore/../stdsimd/coresimd/mod.rs": No such file or directory (os error 2)
   --> /home/travis/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/src/libcore/lib.rs:199:5
    |
199 | mod coresimd;
    |     ^^^^^^^^
error: aborting due to previous error
error: Could not compile `core`.
To learn more, run the command again with --verbose.

@thejpster See this issue.

1 Like

Congratulations and thank you for getting the intrinsics into the standard library.

What’s the status of accompanying this with moving the cross-ISA simd crate (without its architecture-specific submodules) to core::simd?

There is a PR in stdsimd that implements boolean vectors and the reductions, but it doesn't expose portable shuffles nor portable gather/scatters yet.

1 Like

+1 to this. After documenting how to appropriately set RUSTFLAGS throughout my crate, I finally released it only to discover that it also broke docs.rs:

https://docs.rs/crate/yubihsm/0.1.0/builds/90580

Offhand I'm not even sure how to solve this. I opened a docs.rs issue

AFAIK it’s currently impossible to enable target features for rustdoc build. For building docs I’ve introduced ignore_target_feature_check, which is enabled for docs.rs.

If your crate does not compile on any of the tier-1 targets, then docs.rs cannot currently generate documentation for it. (see EDIT below).

This workaround of basically "making your crate compile on any/all of the tier-1 targets" might or might not be a good idea for your crate (depends on the crate).

But cargo-travis uploads your docs, compiled with whatever flags you'd like, to gh-pages, and you can link those from crates.io. You can even compile your docs with multiple flags, and include multiple docs versions, for different targets, or combinations of targets and target features. This might be a better option than synthetically making a crate compile in a target in which it shouldn't be used just for the sake of having docs.rs support.

EDIT: the following should work with docs.rs and is IMO better than artificially making a crate compile without features:

[package.metadata.docs.rs]
rustc-args = [ "-C target-feature=+..." ]

As I’ve said this feature only disables target_feature check, target_arch check is still active. Even without explicit check compilation would’ve failed, because for other targets x86 intrinsics will be disabled.

EDIT: I’ll try to test rustc-args approach in the next crate version.

Sure but what can we do about this? Some crates just explicitly not want to work on all targets, and I think that's fine.

This topic was automatically closed 90 days after the last reply. New replies are no longer allowed.