You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
I wanted to use tuple in my code for wasm application. When i tried to compile my code to wasm using wasm32-unknown-unknown code is compiled but its not returning any return. But I see multi-value is recently supported by webassembly community.
How can I use multivalue ?
My sample example (Note: I'm not using external library like wasm-bindgen as i want to test with pure LLVM backend)
#[no_mangle]
pub extern fn test(x:u64, y:u64) -> (u64, u64) {
(x + y, x - y)
}
My wasm code looks like
LLVM version: 9
Please suggest in this feature
Thanks
Multivalue support is a target feature. You need to pass -C target-feature=+multivalue to rustc, for it to use it. It then emits the code as you would expect: https://rust.godbolt.org/z/KxUavA
@CryZe Thanks for info.
I wanted to run it with cargo I tried cargo build --release -Zmultitarget --target=wasm32-unknown-unknown --target-feature=+multivalue
But ended up with errors
error: Found argument '--target-feature' which wasn't expected, or isn't valid in this context
Did you mean --target-dir?
USAGE:
cargo build --release --target <Build for the target triple>... --target-dir <DIRECTORY>
For more information try --help
All of this makes me think about linking issue. Let's try something different:
test_wasm on master [?] is 📦 v0.1.0 via 🦀 v1.46.0
❯ rustc --crate-type cdylib --target wasm32-unknown-unknown src/lib.rs -C opt-level=3 --emit obj -C target-feature=+multivalue
warning: `extern` fn uses type `(i32, i32)`, which is not FFI-safe
--> src/lib.rs:2:44
|
2 | pub extern "C" fn magic(a: i32, b: i32) -> (i32, i32) {
| ^^^^^^^^^^ not FFI-safe
|
= note: `#[warn(improper_ctypes_definitions)]` on by default
= help: consider using a struct instead
= note: tuples have unspecified layout
warning: 1 warning emitted
test_wasm on master [?] is 📦 v0.1.0 via 🦀 v1.46.0
❯ wasm-objdump -d lib.o
lib.o: file format wasm 0x1
Code Disassembly:
000066 func[0] <magic>:
000067: 20 01 | local.get 1
000069: 20 00 | local.get 0
00006b: 6a | i32.add
00006c: 20 00 | local.get 0
00006e: 20 01 | local.get 1
000070: 6b | i32.sub
000071: 0b | end
This looks fine! Let's try to link it.
test_wasm on master [?] is 📦 v0.1.0 via 🦀 v1.46.0
❯ wasm-ld lib.o -o libtest.wasm --shared
test_wasm on master [?] is 📦 v0.1.0 via 🦀 v1.46.0 took 5s
❯ wasm-objdump -d libtest.wasm
libtest.wasm: file format wasm 0x1
0000021: error: invalid function result count 2, only 1 bytes left in section
Code Disassembly:
0000a7 func[0] <__wasm_call_ctors>:
0000a8: 10 01 | call 1 <__wasm_apply_relocs>
0000aa: 0b | end
0000ac func[1] <__wasm_apply_relocs>:
0000ad: 0b | end
0000af func[2] <magic>:
0000b0: 20 01 | local.get 1
0000b2: 20 00 | local.get 0
0000b4: 6a | i32.add
0000b5: 20 00 | local.get 0
0000b7: 20 01 | local.get 1
0000b9: 6b | i32.sub
0000ba: 0b | end
Ok, this is the exact same issue we tried to use normal compilation using cargo. It looks like there are no options to make the linker aware we are using multivalue (maybe it is enabled by default). In any case,
test_wasm on master [?] is 📦 v0.1.0 via 🦀 v1.46.0
❯ wasm-ld --version
LLD 10.0.1
I just realized that it is possible to use emscripten for the linking stage, after the generation of the object files. The generated wasm file is valid, therefore is definitely an issue with the linker.
EDIT: I think this is not the real issue, see my comment below.
@dodomorandi I faced the exactly the same issue when I compile rust code to wasm. The generated wasm file is invalid with pure LLVM.
(In my case, I wanted to use LLVM only not emscripten )
I started thinking I am very wrong about the issue: yesterday I just realized that maybe the std need to be compiled with multivalue enabled, otherwise there is some sort of incompatibility between object files. This makes sense with the kind of errors I am encountering, and the only issue with the linker is not notifying that you are trying to link together files that should not.
However, I am still unable to create a working example using -Z build-std in nightly. I am trying the following, without success -- maybe some of you know how to tackle down the issue.
Ouch, I just though "hey, why didn't I try xargo??"... but rustc did not like that:
> cat Xargo.toml
[target.wasm32-unknown-unknown.dependencies.std]
features = []
> RUSTFLAGS="-C target-feature=+multivalue" xargo +nightly build --target wasm32-unknown-unknown
warning: Patch `rustc-std-workspace-std v1.99.0 (/home/user/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/rustc-std-workspace-std)` was not used in the crate graph.
Check that the patched package version and available features are compatible
with the dependency requirements. If the patch has a different version from
what is locked in the Cargo.lock file, run `cargo update` to use the new
version. This may also occur with an optional dependency that is not enabled.
Compiling compiler_builtins v0.1.36
Compiling core v0.0.0 (/home/user/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/core)
Compiling libc v0.2.79
Compiling cc v1.0.60
Compiling dlmalloc v0.1.4
Compiling std v0.0.0 (/home/user/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/std)
Compiling unwind v0.0.0 (/home/user/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/unwind)
Compiling rustc-std-workspace-core v1.99.0 (/home/user/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/rustc-std-workspace-core)
Compiling alloc v0.0.0 (/home/user/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/alloc)
Compiling cfg-if v0.1.10
Compiling rustc-demangle v0.1.18
Compiling panic_abort v0.0.0 (/home/user/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/panic_abort)
error: could not compile `compiler_builtins`
Caused by:
process didn't exit successfully: `rustc --crate-name compiler_builtins /home/user/.cargo/registry/src/github.com-1ecc6299db9ec823/compiler_builtins-0.1.36/src/lib.rs --error-format=json --json=diagnostic-rendered-ansi,artifacts --crate-type lib --emit=dep-info,metadata,link -C opt-level=3 -C embed-bitcode=no --cfg 'feature="compiler-builtins"' --cfg 'feature="core"' --cfg 'feature="default"' --cfg 'feature="rustc-dep-of-std"' -C metadata=635019da5e105c8b -C extra-filename=-635019da5e105c8b --out-dir /tmp/xargo.mX5YtAnFkwJX/target/wasm32-unknown-unknown/release/deps --target wasm32-unknown-unknown -L dependency=/tmp/xargo.mX5YtAnFkwJX/target/wasm32-unknown-unknown/release/deps -L dependency=/tmp/xargo.mX5YtAnFkwJX/target/release/deps --extern core=/tmp/xargo.mX5YtAnFkwJX/target/wasm32-unknown-unknown/release/deps/librustc_std_workspace_core-4718ce578524c9f5.rmeta --cap-lints allow -C target-feature=+multivalue --sysroot /home/user/.xargo -Z force-unstable-if-unmarked --cfg 'feature="unstable"' --cfg 'feature="mem"'` (signal: 7, SIGBUS: access to undefined memory)
warning: build failed, waiting for other jobs to finish...
error: build failed
error: `"cargo" "build" "--release" "--manifest-path" "/tmp/xargo.mX5YtAnFkwJX/Cargo.toml" "--target" "wasm32-unknown-unknown" "-p" "std"` failed with exit code: Some(101)
note: run with `RUST_BACKTRACE=1` for a backtrace
Notice that SIGBUS error at the end of the cause...
With further investigation, the -target-abi experimental-mv seems to be a crucial part. In addition, rust should return the value as a struct (maybe the target-abi will effect that?).
LLVM 17 contains a patch to fix libcalls signatures with multivalue.
With it being merged in #114048, multivalue compilation is now working on latest nightly !
Due to the ABI mismatch thing, it still requires -Zbuild-std though.
wasi-libc is precompiled and even building std won't help with that. Long term LLVM will probably enable multivalue by default, resolving this entire issue.
wasi-libc is precompiled and even building std won't help with that.
I feared as much … is this something that Rust could fix by rebuilding wasi-libc with the requested target features, or is it better to use a variant of wasm-bindgen’s multivalue wrapper for exports (I don’t use wasm-bindgen in my crate yet so I’m not quite sure here what to do about the shadow stack the wrapper uses)?
Now that multivalue is enabled by default, yet Rust still doesn't produce multi-value return for WebAssembly targets. None of the demo I found in this issue nowadays yields multi-value return with the latest rustc, and as described in the blog post last year:
there is no longer any possible method of writing a function in Rust that returns multiple values at the WebAssembly function type level.
Given this situation, should this issue be re-opened?
Reacted by Shua, naskya, Matan Kushner, Vladimir Cherkasov, ben, dbartussek, Flavio Castelli and Zen
Activity
CryZe commentedon Jun 26, 2020
Multivalue support is a target feature. You need to pass
-C target-feature=+multivalueto rustc, for it to use it. It then emits the code as you would expect: https://rust.godbolt.org/z/KxUavAAchalaSB commentedon Jun 29, 2020
@CryZe Thanks for info.
I wanted to run it with
cargoI triedcargo build --release -Zmultitarget --target=wasm32-unknown-unknown --target-feature=+multivalueBut ended up with errors
Muqito commentedon Jun 30, 2020
@AchalaSB Don't know if it helps in any way; but I can run the following with
rustcrustc -C target-feature=+multivalue --target=wasm32-unknown-unknown {input}AchalaSB commentedon Jul 1, 2020
@Muqito with rustc we can do. Since i have some library dependencies i need to run it with
cargo buildyodaldevoid commentedon Jul 2, 2020
will
cargo rustc --release -Zmultitarget --target=wasm32-unknown-unknown -- -C target-feature=+multivaluework?dodomorandi commentedon Sep 12, 2020
I am performing some tests with multivalue compilation, and I am encountering a strange issue. Take the following code:
(Almost the same thing showed by @AchalaSB)
This emits to the following asm (using
--emit asm, kinda misleading when talking about wasm 😅)Fine! Let's compile it and try to convert it back to wat:
Let's try to see what
wasm-objdumpsees:Just to be sure, let's try to write the corresponding (simplified) wat file, convert it to wasm and back to wat:
All of this makes me think about linking issue. Let's try something different:
This looks fine! Let's try to link it.
Ok, this is the exact same issue we tried to use normal compilation using cargo. It looks like there are no options to make the linker aware we are using multivalue (maybe it is enabled by default). In any case,
And I am on Arch Linux, if it could help.
dodomorandi commentedon Sep 12, 2020
I just realized that it is possible to use emscripten for the linking stage, after the generation of the object files. The generated wasm file is valid, therefore is definitely an issue with the linker.
EDIT: I think this is not the real issue, see my comment below.
AchalaSB commentedon Sep 15, 2020
@dodomorandi I faced the exactly the same issue when I compile rust code to wasm. The generated wasm file is invalid with pure LLVM.
(In my case, I wanted to use LLVM only not emscripten )
dodomorandi commentedon Sep 15, 2020
I started thinking I am very wrong about the issue: yesterday I just realized that maybe the std need to be compiled with
multivalueenabled, otherwise there is some sort of incompatibility between object files. This makes sense with the kind of errors I am encountering, and the only issue with the linker is not notifying that you are trying to link together files that should not.However, I am still unable to create a working example using
-Z build-stdin nightly. I am trying the following, without success -- maybe some of you know how to tackle down the issue.nomeata commentedon Nov 2, 2020
Any progress here? I’d be curious about how to create a rust module that imports and exports functions using Wasm multi-value features.
dodomorandi commentedon Nov 16, 2020
Ouch, I just though "hey, why didn't I try xargo??"... but rustc did not like that:
Notice that
SIGBUSerror at the end of the cause...zimond commentedon Dec 24, 2020
So is there a possible working solution for this?
blaind commentedon Jan 17, 2021
I've been trying to investigate this further. No solution yet, but some pointers:
Based on the Tweet and LLVM commit code (
getTarget().getABI() == "experimental-mv"), the experimental-mv ABI should be set, but how?test.rs:
rustc version:
Multivalue feature is visible
Compiling as .wasm
Produces following LLVM (test.ll):
(knowing nothing of LLVM syntax, the
unnamed_addrandundefpoint out, what are those?test.o contents (
xxd test.o)Linking (
$ wasm-ld-11 --verbose test.o -o test.wasm --shared)Which displays: (
$ wasm2wat --enable-multi-value test.wasm)Same also if trying with https://webassembly.github.io/wabt/demo/wasm2wat/
Contents (
$ xxd test.wasm)Direct compilation to .wasm produces a large file (1.5MB)
Wasm2wat says similar as above.
objdump:
I also tried with no success:
#[allow(improper_ctypes_definitions)])[i32; 2]instead of a tuple(i32, i32)wasm32-wasiandwasm32-unknown-emscriptentargets (did not fail, but produces no multi-value wasm)struct(i32, i32)andstruct { a: i32, b: i32 }With clang, following can be produced
C contents:
$ cat test.cppEmit LLVM (test.ll):
Compile to test.wasm
Produced wat:
blaind commentedon Jan 17, 2021
With further investigation, the
-target-abi experimental-mvseems to be a crucial part. In addition, rust should return the value as a struct (maybe the target-abi will effect that?).I tried the -C values with no help:
Some relevant tickets:
#80970
#60617 (comment)
39 remaining items
eastside commentedon Aug 9, 2023
@oxalica, That makes a lot of sense. But...
I've tried this, and I'm getting a similar compiler error. Just for my own sanity, does this command look right?
RUSTFLAGS="-C target-feature=+multivalue" cargo build --target=wasm32-unknown-unknown -Zbuild-std=panic_abort,stdYou can find the repo that I'm using here.
Full output:
CryZe commentedon Aug 9, 2023
We are going in like the 5th circle now. The current up to date comment regarding the bug is here: #73755 (comment)
a1phyr commentedon Aug 10, 2023
LLVM 17 contains a patch to fix libcalls signatures with multivalue.
With it being merged in #114048, multivalue compilation is now working on latest nightly !
Due to the ABI mismatch thing, it still requires
-Zbuild-stdthough.daxpedda commentedon Aug 10, 2023
Works on my end as well now.
CryZe commentedon Aug 10, 2023
Same for me. So I guess this can be closed now?
daxpedda commentedon Aug 10, 2023
@workingjubilee you indicated in #73916 that this still requires a test, but we don't need two open issues for that I think.
workingjubilee commentedon Aug 31, 2023
Agreed.
lib(rust): Use packed(u64) tuple when `+multivalue` feature not defined
juntyr commentedon Oct 21, 2023
Using rustc 1.75.0-nightly (249624b 2023-10-20), I just came across this issue again in a wasm32-wasi crate:
which is built using
RUSTFLAGS="-C target-feature=+multivalue" cargo +nightly build --target wasm32-wasi -Zbuild-std=panic_abort,stdCryZe commentedon Oct 21, 2023
wasi-libc is precompiled and even building std won't help with that. Long term LLVM will probably enable multivalue by default, resolving this entire issue.
juntyr commentedon Oct 21, 2023
I feared as much … is this something that Rust could fix by rebuilding wasi-libc with the requested target features, or is it better to use a variant of wasm-bindgen’s multivalue wrapper for exports (I don’t use wasm-bindgen in my crate yet so I’m not quite sure here what to do about the shadow stack the wrapper uses)?
Auto merge of rust-lang#117457 - daxpedda:wasm-nontrapping-fptoint, r…
Auto merge of rust-lang#117457 - daxpedda:wasm-nontrapping-fptoint, r…
upsuper commentedon Oct 29, 2025
Now that
multivalueis enabled by default, yet Rust still doesn't produce multi-value return for WebAssembly targets. None of the demo I found in this issue nowadays yields multi-value return with the latest rustc, and as described in the blog post last year:Given this situation, should this issue be re-opened?