Return value packing for Option<T> and Result<T,E> on WebAssembly #65882
Labels
A-codegen
Area: Code generation
C-enhancement
Category: An issue proposing an enhancement or a PR with one.
I-slow
Issue: Problems and improvements with respect to performance of generated code.
O-wasm
Target: WASM (WebAssembly), http://webassembly.org/
T-compiler
Relevant to the compiler team, which will review and decide on the PR/issue.
I'm looking at how
Result<T,E>
andOption<T>
return values get handled on the WebAssembly target, using integral types as theT
and small fieldless enums as theE
type. It seems hard to predict when Rust will use stack allocation for the return value, and some optimizations that happen on native platforms like x86-64 Linux aren't happening where I expect them.(I'm aware that internal Rust ABIs are unstable, but it'd nice to be able to reason about performance on critical paths, so I'm checking this out in detail before building a pipeline that depends on Results or Options in a tight interpreter loop.)
Tested some example code like:
with similar variants for u8, u16, u32, and u64 returns. The
MyErr
enum is small enough to fit in less than a byte itself forResult
returns.On a Linux or macOS x86-64 build (with the benefit of having native support for two return values in registers) I get:
On a WebAssembly build, I get:
Couple big things surprised me here. First, while on native x86-64
Option<T>
is well optimized using two registers,Result<T,E>
doesn't consistently get the same treatment. Perhaps because conceptually the enum payload is a separate data byte and it complicates things?Second, none of the Option types get optimized into integral values on WebAssembly, where there's no multiple return value handling yet but return types up to 64 bits are available.
Third, while
Result<u16,MyErr>
gets packed into a 32-bit word on WebAssembly, theu8
version is not though it would fit handily in a 32-bit word too, nor is theu32
version packed into a 64-bit word like on native. (There might be something weird with my u8 version, like it's optimizing out the MyErr or something.)As for
Result<u64,MyErr>
, that's using stack as expected.In summary, on WebAssembly:
Option<T>
is not getting "register"-packed at any size, causing transfer of data through memory.Result<u8, MyErr>
andResult<u32, MyErr>
should be packable into 32-bit and 64-bit return values, but are not. It's unclear why.Result<u64, MyErr>
as stack transfer remains optimal until some future day when WebAssembly gains multiple return values.Thanks for any advice or explanations!
The text was updated successfully, but these errors were encountered: