saulecabrera opened PR #7535 from saulecabrera:winch-multi-value
to bytecodealliance:main
:
This change adds initial support for the Multi-Value proposal to Winch, focusing on function calls, support for Multi-Value for blocks will be added on top of this change in a different pull request.
This change is divided into two main parts:
- Infrastructure changes needed to support Multi-Value
- Handling Multi-Value returns for function calls
Infrastructure changes needed to support Multi-Value
Some notable changes were needed in order to support this proposal, namely:
- Introducing the notion of
ABIOperands
and rewriting theABIParams
andABIResults
in terms ofABIOperands
.- In Winch's default calling convention, results are stored in reverse order: if a function produces multiple results, the first result is stored in a memory location and the last result is stored in a register; given that function results are captured in the value stack after a function call, this approach makes it trivial to maintain the following value stack invariants:
- Spilled memory values always precede register values
- Spilled values are stored from oldest to newest, matching their respective locations on the machine stack.
- Introducing type-sized spills: Prior to this change, only floats produced type-sized spills, this created an inconsistency on how slots for results are handled and made it harder to manage the stack for multiple-results; this change introduces type-sized spills for integer and floats, making the spilling strategy uniform across the compiler. This might introduce some overhead, since this change is now introducing two instructions were previously there only used to be one (e.g.
push
vssub + mov
). My intention is to profile, and try to improve this strategy if possible later on.Handling Multi-Value returns for function calls
The approach for handling multiple results for function calls involves:
Adding an implicit extra parameter to the
ABIParams
definition, when a function returns multiple values; from the callee's perspective, this parameter is treated like any other "special" parameter (e.gVMContext
), to which, we give it a well knowLocalSlot
for later referencing when storing the return values. From the caller's perspective, extra stack space is created before the call, and the address to that space is passed in to the callee, via the return pointer parameter and once the function returns, the values in the created space are captured as values in the value stack.<!--
Please make sure you include the following information:
If this work has been discussed elsewhere, please include a link to that
conversation. If it was discussed in an issue, just mention "issue #...".Explain why this change is needed. If the details are in an issue already,
this can be brief.Our development process is documented in the Wasmtime book:
https://docs.wasmtime.dev/contributing-development-process.htmlPlease ensure all communication follows the code of conduct:
https://github.com/bytecodealliance/wasmtime/blob/main/CODE_OF_CONDUCT.md
-->
saulecabrera requested fitzgen for a review on PR #7535.
saulecabrera requested wasmtime-compiler-reviewers for a review on PR #7535.
saulecabrera requested wasmtime-core-reviewers for a review on PR #7535.
saulecabrera updated PR #7535.
saulecabrera updated PR #7535.
saulecabrera edited PR #7535:
This change adds initial support for the Multi-Value proposal to Winch, focusing on function calls, support for Multi-Value for blocks will be added on top of this change in a different pull request.
This change is divided into two main parts:
- Infrastructure changes needed to support Multi-Value
- Handling Multi-Value returns for function calls
Infrastructure changes needed to support Multi-Value
Some notable changes were needed in order to support this proposal, namely:
- Introducing the notion of
ABIOperands
and rewriting theABIParams
andABIResults
in terms ofABIOperands
.- In Winch's default calling convention, results are stored in reverse order: if a function produces multiple results, the first result is stored in a memory location and the last result is stored in a register; given that function results are captured in the value stack after a function call, this approach makes it trivial to maintain the following value stack invariants:
- Spilled memory values always precede register values
- Spilled values are stored from oldest to newest, matching their respective locations on the machine stack.
- Introducing type-sized spills: Prior to this change, only floats produced type-sized spills, this created an inconsistency on how slots for results are handled and made it harder to manage the stack for multiple-results; this change introduces type-sized spills for integer and floats, making the spilling strategy uniform across the compiler. This might introduce some overhead, since this change is now, in the 32-bit case, introducing two instructions were previously there only used to be one (e.g.
push
vssub + mov
). My intention is to profile, and try to improve this strategy if needed, later on.Handling Multi-Value returns for function calls
The approach for handling multiple results for function calls involves:
Adding an implicit extra parameter to the
ABIParams
definition, when a function returns multiple values; from the callee's perspective, this parameter is treated like any other "special" parameter (e.gVMContext
), to which, we give it a well knowLocalSlot
for later referencing when storing the return values. From the caller's perspective, extra stack space is created before the call, and the address to that space is passed in to the callee, via the return pointer parameter and once the function returns, the values in the created space are captured as values in the value stack.<!--
Please make sure you include the following information:
If this work has been discussed elsewhere, please include a link to that
conversation. If it was discussed in an issue, just mention "issue #...".Explain why this change is needed. If the details are in an issue already,
this can be brief.Our development process is documented in the Wasmtime book:
https://docs.wasmtime.dev/contributing-development-process.htmlPlease ensure all communication follows the code of conduct:
https://github.com/bytecodealliance/wasmtime/blob/main/CODE_OF_CONDUCT.md
-->
fitzgen submitted PR review:
LGTM but I'm still a little sketched out by those disassembly changes where I feel like I'm only seeing one half of a change or something like that. Maybe you can explain what is going on?
fitzgen submitted PR review:
LGTM but I'm still a little sketched out by those disassembly changes where I feel like I'm only seeing one half of a change or something like that. Maybe you can explain what is going on?
fitzgen created PR review comment:
Could we document what the
map
closure is supposed to do here? Was not immediately obvious to me when reading the code.
fitzgen created PR review comment:
This seems like it is unnecessarily setting us up for porting issues in the future when we have a 32-bit target. Can we just put the size directly or use
mem::size_of::<u32>()
or something instead?
fitzgen created PR review comment:
Ah, great!
fitzgen created PR review comment:
Is this an expected/intended change in this first commit? I thought this was purely a refactoring to prep for multi-value, and I wouldn't expect any functional changes. Certainly not ones where we are changing from where we are pushing values to the stack when I don't see any corresponding changes in how we pop values from the stack.
But maybe this is addressed in follow up commits that I haven't gotten to yet...
fitzgen created PR review comment:
Documentation is out of sync with the code: it returns a set not an iterator.
fitzgen created PR review comment:
Ditto regarding
map
fitzgen created PR review comment:
:eyes:
fitzgen created PR review comment:
debug_assert_eq!
will give better diagnostics on panic.
saulecabrera updated PR #7535.
saulecabrera submitted PR review.
saulecabrera created PR review comment:
I ended up moving the definition to the implementation of each ABI, that way once it'll be easier to integrate once we support 32-bit targets.
saulecabrera submitted PR review.
saulecabrera created PR review comment:
Fixed!
saulecabrera submitted PR review.
saulecabrera created PR review comment:
Fixed!
saulecabrera submitted PR review.
saulecabrera created PR review comment:
Fixed!
saulecabrera submitted PR review.
saulecabrera created PR review comment:
It's indeed intended, I just forgot to mention it in the commit message: I realized that the slot for the
VMContext
was not aligned, so I introduced alignment for it, similar to what I did for the return pointer.In the first commit, that is here https://github.com/bytecodealliance/wasmtime/pull/7535/commits/5dcefe38b9dc4cac3f24bf9f4d0eb20f43f9b6a1#diff-b396908c6cc30abb2ad12e93c9443d5b8875dd320980cde6896068f5e5cbf4c1R101-R106; hopefully this clarifies things!
saulecabrera submitted PR review.
saulecabrera created PR review comment:
Fixed
saulecabrera edited PR review comment.
fitzgen submitted PR review.
fitzgen created PR review comment:
That makes sense -- thanks for the explanation!
saulecabrera merged PR #7535.
Last updated: Dec 23 2024 at 12:05 UTC