rust-lang / rust

Empowering everyone to build reliable and efficient software.
https://www.rust-lang.org
Other
96.6k stars 12.48k forks source link

WebAssembly platform requirements are not well documented #119811

Closed stephanemagnenat closed 2 weeks ago

stephanemagnenat commented 8 months ago

Location

README.md and WebAssembly book (https://rustwasm.github.io/docs/book/)

Summary

In version 1.70 Rust added some requirements for WebAssembly targets. This makes Wasm binaries compiled with Rust (at least with default options/out of the box std) incompatible with older runtime environments, in particular not-so-old iOS safari (https://webassembly.org/features/). Here is for example the support for Safari iOS 15.5 simulator:

safari-15_5-wasm-support

I searched but did not find any place where these requirements are written down. I think that this is a problem.

nagisa commented 8 months ago

In principle Rust can produce binaries that only target the core subset of wasm 1.0 just fine. You do need to set some additional options with -Ctarget-features and build your own standard libraries though.

But point taken, https://doc.rust-lang.org/nightly/rustc/platform-support.html is missing dedicated pages on the wasm target that could contain this information.

nagisa commented 8 months ago

The 2nd sentence right after the one you quoted outlines exactly what you need to do to take advantage of rustc’s capability to emit outputs to the wasm 1.0 spec (or any superset of it:)

You do need to set some additional options with -Ctarget-features and build your own standard libraries though.

Make sure to do this and report back if you're still seeing the unexpected instructions/types/other entities after rustc is told to produce wasm binaries the way you need them to be.

Could such a compiler feature be enabled by a crate in the dependency tree?

AFAIK, not for WASM.

stephanemagnenat commented 8 months ago

Sorry, I realized I misunderstood your answer and deleted my post while you were answering it.

Do you know how to show which features are enabled by default for a given target? I searched and did not find. I'm trying to discover whether simd128 is enabled by default on wasm32-unknown-unknown nowadays. As it seems to be because I am seeing v128 types in the emitted wasm, even though I disabled the feature by "-C target-feature=-simd128" in an environment variable RUSTFLAGS. It would be surprising to me that std is built with that feature by default on wasm32, but maybe it is.

nagisa commented 8 months ago

Hm, I'm actually not sure why you might be seeing simd128 in your modules. As far as I can tell it is not enabled by default for any wasm target.

In order to print out features used you should look for target_feature lines in:

rustc --print cfg --target=wasm32-unknown-unknown -Ctarget-feature=+simd128

For what it is worth I’ve been using this exact target at my $DAYJOB with a pretty primitive runtime and it has been working largely OOB if my memory serves me right. So it indeed could have something to do with your dependencies possibly using something like #[target_feature(enable = "simd128")]? Not sure!

stephanemagnenat commented 8 months ago

It seems that the memchr package was built with target_feature = "simd128" as I see this WASM function:

(func $memchr::arch::wasm32::simd128::packedpair::Finder::find_impl::h5393de7f1a212dde (type 23) (param i32 i32 i32 i32 i32 i32)
    (local i32 ... i32 v128 v128 v128 v128 v128 v128 v128 v128 v128 v128 v128 v128 v128 v128 v128 v128 v128 v128 v128 v128 v128 v128 v128 v128 v128 v128 v128 v128)

What I am not sure is whether 1. this was integrated with the standard library and then imported indirectly to my project, or 2. somehow one of the dependency managed to enable it by itself. I tend to favor 1 but I'm not sure. That is why it would be great for such things to be documented :-)

stephanemagnenat commented 8 months ago

For reference, I asked on the user forum about how the std lib is built.

stephanemagnenat commented 8 months ago

@nagisa I confirm that as of version 1.75, the standard library is not using any WebAssembly SIMD instructions. Here is my test:

for file in $HOME/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/wasm32-unknown-unknown/lib/*; do
    ar -x "$file"
done
for file in *.o; do
    if wasm-objdump -d "$file" | grep -q 'v128'; then
        echo "$file"
    fi
done

which shows nothing, so they get pulled in by the memchr package through some of my dependencies.

nagisa commented 8 months ago

You yourself pointed out which crate produces the v128 types: memchr. It uses #[target_feature(enable="simd128")] to enable emission of these types, regardless of the global configuration it looks like. This is usually fine for other architectures, but rarely for wasm, so it might make sense to file an issue over there.

stephanemagnenat commented 8 months ago

I fully agree and I just opened an issue there: BurntSushi/memchr#144

alexcrichton commented 1 month ago

As a heads up I've proposed that https://github.com/rust-lang/rust/pull/128511 close this issue with documentation of how to target MVP wasm.