-
Notifications
You must be signed in to change notification settings - Fork 42
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Support branch instructions that define their blockparams #186
Comments
@bjorn3 and I were discussing this just now; to add a little more background:
A thought does occur to me though: if we relax the second point above, this may become a bit simpler. Working backward from what we want to happen in the "backend" of regalloc: we want to allocate new register(s) for the call results; we want their liverange to start with the underlying call instruction. This is a little different from blockparams, which logically start at the successor block, so we have a little "stub" of a liverange just over the invoke/branch instruction anyway. What if we take that further, relax the results-as-blockparams, and do something like:
basically, the idea is to construct the RA2 problem as a conservative superset of the required allocations: the invoke results are allocated at the call, and in-scope in all blocks they dominate as normal, including the normal return path and exceptional return path; the fact that the call will not have written the result on unwind is a fact at a higher semantic level that we respect (by not reading the register on that path) in the CLIF. The remaining question is then: can branches def values? I can't think of a specific case or check that would break this, but there may be some subtle interaction. In particular I believe that edge-moves are not a problem as long as invoke has two targets: this will force edge-moves to be placed in the successor blocks' heads rather than just before the branch. (The edge-moves come logically after the def so it would be a problem otherwise.) Others have any thoughts? |
In the unwind case there are also return values. These may be of different types than for the regular-return case, but generally do occupy the same registers. These need to be supported as they are often used to pass around the exception object itself. |
This actually already works in regalloc2 without any changes needed. First, we must differentiate between 2 types of branches:
Notably, it's possible for You can build an The last commit in #170 extends the fuzzer to test this case. |
Neat, that's I think essentially what I describe above except two defs (exception ptr as well). Hopefully a fairly straightforward change on the producer side! |
Both the normal and exception return cases can have a variable amount of return values. For exception returns it is up to two registers. I guess one way to handle this would be to look at the signature of the called function to know how many normal return values there are and treat the rest as exception return values.
How can I lower the block calls on the clif ir side to something that avoids blockparams on the regalloc side? |
I think a reasonable design might be:
|
So to add an example, if we have
then the regalloc metadata for the invoke is:
|
Cross posting bytecodealliance/rfcs#36 here because I think both discussions should be aware of each other. Random notes on my preferences for the clif design side of things, since it is relevant to the discussion here about how we would lower/translate this to regalloc2 input:
|
There is no fundamental reason why this is necessary. In fact for wasm lowering it may be beneficial if this restriction doesn't exist sich that throwing an exception can be done by directly jumping to the cleanup block while still sharing this block with the unwind target for calls. With this restriction in place wasm lowering would need to add an extra block whose sole purpose is to be marked as landingpad and jump to the real cleanup block. Edit: It may be necessary for another block to be inserted in between when lowering to vcode for any register moves, but that has to be done anyway when two calls share a landingpad. |
The context of this discussion is how to present the instruction to RA2, so yes, my thinking is mostly from that side. That said, I think this issue is a little more subtle than it may seem; will write up some comments over in the proposal (I hadn't had a chance to read it when posting the above as it had just appeared!). |
This would allow an
invoke
instruction to define a virtual register representing the return value and then pass this as as blockparam to the regular return block. And similarly define a virtual register representing the landingpad argument and pass it as blockparam to the block for the landingpad.The text was updated successfully, but these errors were encountered: