s390x: Migrate branches and traps to ISLE#3724
Conversation
In order to migrate branches to ISLE, we define a second entry point `lower_branch` which gets the list of branch targets as additional argument. This requires a small change to `lower_common`: the `isle_lower` callback argument is changed from a function pointer to a closure. This allows passing the extra argument via a closure. Traps make use of the recently added facility to emit safepoints from ISLE, but are otherwise straightforward.
fitzgen
left a comment
There was a problem hiding this comment.
Looks great modulo a couple nitpicks below, thanks!
| (decl safepoint (SideEffectNoResult) ValueRegs) | ||
| (rule (safepoint (SideEffectNoResult.Inst inst)) | ||
| (let ((_ Unit (emit_safepoint inst))) | ||
| (value_regs_invalid))) |
There was a problem hiding this comment.
I think this should go in the shared prelude, next to value_regs_none.
| #[inline] | ||
| fn emit_safepoint(&mut self, inst: &MInst) -> Unit { | ||
| self.emitted_insts.push((inst.clone(), true)); | ||
| } |
There was a problem hiding this comment.
And then I would expect this to go into wasmtime/cranelift/codegen/src/machinst/isle.rs
| (decl emit_safepoint (MInst) Unit) | ||
| (extern constructor emit_safepoint emit_safepoint) |
There was a problem hiding this comment.
And this should be in the prelude as well.
There was a problem hiding this comment.
I see that emit actually isn't in the prelude, but we do use it from the prelude. So we should probably move emit to the prelude as well, since in practice it has to be the same declaration across all backends anyways. Happy to have that as part of this updated PR or we can do it in another PR.
There was a problem hiding this comment.
Yes, that's why I didn't put it in the prelude ...
I agree it makes sense to move emit / emit_safepoint there, but then we should also move the implementations to machinst/isle.re, right?
I'd be happy to do that, but I think it would be better to do it in another PR, as it will touch all back-ends.
There was a problem hiding this comment.
Yes, we wouldn't necessarily have to move the implementations as well, nothing is stopping us from implementing the ISLE context's emit trait method once for each backend even when the decl is in the prelude.
In fact the x86_64 implementation is a little different, in that it calls a mov_mitosis method on each inst in emitted_insts, and if we made this code common then we would need to add such a method to the MachInst trait or something.
So I think we can move just the ISLE decl into the prelude without moving the rust trait implementations at all. Happy to have this in a follow up PR.
There was a problem hiding this comment.
Ah, I see. But even if we don't move the implementaton, once the decl is in the prelude as extern constructor, every back-end must implement it or it won't compile any more. So we'll still need to touch all back-ends. (In fact, with the x86 mov_mitosis implementation, I'm not sure exactly how the safepoint variant would work. I guess only the last instruction in the list should be the safepoint?)
There was a problem hiding this comment.
once the
declis in the prelude asextern constructor, every back-end must implement it or it won't compile any more.
Correct. (Also, it is already the case that every backend must implement it or the ISLE won't compile because we are calling emit and assuming it is declared from inside the prelude already, it just so happens that we have N identical declarations for each backend instead of a single shared declaration in the prelude.)
(In fact, with the x86
mov_mitosisimplementation, I'm not sure exactly how the safepoint variant would work. I guess only the last instruction in the list should be the safepoint?)
Yeah, I will have to think a bit about how to do this best. I think making only the last instruction a safepoint would work, but we might want to have some debug asserts in there too. Planning on tackling this after I'm done with my newtype wrappers PR by which time this PR will have merged.
There was a problem hiding this comment.
I think making only the last instruction a safepoint would work,
Yeah, I think that's the correct solution -- the expanded list should always have the form of zero or more moves, followed by the original instruction; and the safepoint bit applies to the latter.
There was a problem hiding this comment.
There are some instructions that always generate their results into a particular register, and so when our SSA-ified version of that instruction wants the result in a temp, we have to generate a move that follows the "real" instruction, so we can have trailing moves as well after move mitosis. This shouldn't be the case for safepoints I don't think (except maybe ABI/calling convention stuff where results are always in rax?) and we should be able to just debug assert this.
|
Can this be merged now or are you waiting on any action from my side? I have other patches I'd like to submit and this is causing merge conflicts ... As to the question of moving |
I think just the nitpicks that we didn't already discuss and agree could wait for follow ups:
|
But that was just what we discussed: As I understand, x64 will need a different |
|
Ah right. Then just the |
I'm happy to do that, but I'd really prefer this to be a separate PR. That will still touch all backends and their generated files, and I'd prefer not to entangle this with this back-end change, which is already quite large as-is ... |
fitzgen
left a comment
There was a problem hiding this comment.
Okay, we can do that in follow ups then.
Thanks! The follow up is now here: #3745 |
In order to migrate branches to ISLE, we define a second entry
point
lower_branchwhich gets the list of branch targets asadditional argument.
This requires a small change to
lower_common: theisle_lowercallback argument is changed from a function pointer to a closure.
This allows passing the extra argument via a closure.
Traps make use of the recently added facility to emit safepoints
from ISLE, but are otherwise straightforward.
@cfallin @fitzgen