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
This is an idea that I've had bouncing around in my head for some time now but I wanted to write it down after discussing it with @sbc100 today in person as well. The basic motivation here is that I'd like to be able to write a function in Rust or C that translates to using multiple returns at the WebAssembly ABI level. The motivation here stems from the component model and the definition of the canonical ABI where right now at most one return value is supported before spilling items to the stack. While not the hardest problem to deal with in the world it'd be nicer to be able to support more return values as immediates instead of stack values (e.g. option<T> or result<T, E>).
Over the years though I've come to think that changing the default WebAssembly C ABI is the wrong way to do this. Recent learnings in the Rust community has shown that CLI flags controlling ABIs is a recipe for disaster as it's (a) easy to get flags misaligned, (b) hinders shipping precompiled artifacts, and (c) requires a fair bit of infrastructure to track what's using what. This means that I've personally concluded that a flag should not be used to change the ABI of a whole object file or compilation unit. Additionally I believe @tlively did some analysis awhile back and concluded that performance wouldn't really be helped all that much, which is also why I don't think it's worth changing the default ABI.
Instead what I'd propose to solve this is to add a new ABI to the documents here. That would translate to a new ABI in LLVM as well. The idea is that each function in C/C++/Rust would be able to define, on a per-function level, the ABI being used. Some properties of this new ABI would be:
Returning an aggregate would "flatten" the aggregate into multiple returns. For example returning #[repr(C)] struct A(i32, i32) in Rust would translate to (result i32 i32).
Any calling convention may be specified by number, allowing target-specific calling conventions to be used. Target specific calling conventions start at 64.
For example we could reserve cc 64, on wasm targets, as the multi-value calling convention. Using this calling convention would require that the feature +multi-value was present, and otherwise it would generate a compiler error saying that the ABI can't be used when such a feature is disabled.
My hope is that this would enable implementing things and start migrating some select APIs, for example generated code, to this new ABI and benefit from multiple return values. This wouldn't interfere with anything else and doesn't need to involve any sort of transition plan from the current ABI to a new ABI. Instead this is a new parallel ABI to the existing one which enables intermixing them if desired. In the future a default change could be considered, but that'd otherwise be orthogonal to this change.
The text was updated successfully, but these errors were encountered:
Generally speaking, I like the idea of ABIs being specifiable per-function. I think this is similar to what you can do on ARM with all the various ABIs that use the various optional hardware that have been added over the years, and I think we can probably take some inspiration from the way those are implemented.
I think there may still end up being e.g. clang flags that change the default for a compile unit, or LLVM backend flags that do likewise. It might be useful for LTO, for example (although LTO optimizations can already change calling conventions, e.g. LTO sets "fastcc" on x86 when possible).
But I think it's worth pursuing, and may well end up being impactful, especially given e.g. the more closed-world nature of emscripten and more use of LTO compared to native platforms.
This is an idea that I've had bouncing around in my head for some time now but I wanted to write it down after discussing it with @sbc100 today in person as well. The basic motivation here is that I'd like to be able to write a function in Rust or C that translates to using multiple returns at the WebAssembly ABI level. The motivation here stems from the component model and the definition of the canonical ABI where right now at most one return value is supported before spilling items to the stack. While not the hardest problem to deal with in the world it'd be nicer to be able to support more return values as immediates instead of stack values (e.g.
option<T>
orresult<T, E>
).Over the years though I've come to think that changing the default WebAssembly C ABI is the wrong way to do this. Recent learnings in the Rust community has shown that CLI flags controlling ABIs is a recipe for disaster as it's (a) easy to get flags misaligned, (b) hinders shipping precompiled artifacts, and (c) requires a fair bit of infrastructure to track what's using what. This means that I've personally concluded that a flag should not be used to change the ABI of a whole object file or compilation unit. Additionally I believe @tlively did some analysis awhile back and concluded that performance wouldn't really be helped all that much, which is also why I don't think it's worth changing the default ABI.
Instead what I'd propose to solve this is to add a new ABI to the documents here. That would translate to a new ABI in LLVM as well. The idea is that each function in C/C++/Rust would be able to define, on a per-function level, the ABI being used. Some properties of this new ABI would be:
#[repr(C)] struct A(i32, i32)
in Rust would translate to(result i32 i32)
.__attribute__((wasm_multivalue)) AggregateReturn foo() { ... }
extern "wasm-multivalue" fn foo() { ... }
Implementation-wise this could use of the
cc <n>
calling convention in LLVM which states:For example we could reserve
cc 64
, on wasm targets, as the multi-value calling convention. Using this calling convention would require that the feature+multi-value
was present, and otherwise it would generate a compiler error saying that the ABI can't be used when such a feature is disabled.My hope is that this would enable implementing things and start migrating some select APIs, for example generated code, to this new ABI and benefit from multiple return values. This wouldn't interfere with anything else and doesn't need to involve any sort of transition plan from the current ABI to a new ABI. Instead this is a new parallel ABI to the existing one which enables intermixing them if desired. In the future a default change could be considered, but that'd otherwise be orthogonal to this change.
The text was updated successfully, but these errors were encountered: